private static void InstallAPP()
    {
        PXR_SceneQucikPreviewEW.PrintLog("installing APP  . . .");

        PXR_DirectorySyncer.CreateDirectory(SQP_BUNDLE_PATH);

        PrebuildProjectSettingUpdate();

        if (string.IsNullOrEmpty(previewIndexPath) || !File.Exists(previewIndexPath))
        {
            string[] editorScenePaths = Directory.GetFiles(PXR_PathHelper.GetPicoXRPluginPath(), SQP_INDEX_NAME, SearchOption.AllDirectories);

            if (editorScenePaths.Length == 0 || editorScenePaths.Length > 1)
            {
                PXR_SceneQucikPreviewEW.PrintError(editorScenePaths.Length + " " + SQP_INDEX_NAME + " has been found, please double check your PicoXR Plugin import.");
                return;
            }
            previewIndexPath = Path.Combine(Application.dataPath, SQP_INDEX_NAME);
            if (File.Exists(previewIndexPath))
            {
                File.Delete(previewIndexPath);
            }
            File.Copy(editorScenePaths[0], previewIndexPath);
        }

        string[] buildScenes = new string[1] {
            previewIndexPath
        };
        string apkOutputPath = Path.Combine(SQP_BUNDLE_PATH, SQP_APK_NAME);

        if (File.Exists(apkOutputPath))
        {
            File.Delete(apkOutputPath);
        }

        var buildPlayerOptions = new BuildPlayerOptions
        {
            scenes           = buildScenes,
            locationPathName = apkOutputPath,
            target           = BuildTarget.Android,
            options          = BuildOptions.Development |
                               BuildOptions.AutoRunPlayer
        };

        BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);

        if (report.summary.result == BuildResult.Succeeded)
        {
            PXR_SceneQucikPreviewEW.PrintSuccess("App is installed.");
        }
        else if (report.summary.result == BuildResult.Failed)
        {
            PXR_SceneQucikPreviewEW.PrintError();
        }
        PostbuildProjectSettingUpdate();
    }
 public static void DeleteCacheBundles()
 {
     try
     {
         if (Directory.Exists(SQP_BUNDLE_PATH))
         {
             Directory.Delete(SQP_BUNDLE_PATH, true);
         }
         DeleteCachePreviewIndexFile();
     }
     catch (Exception e)
     {
         PXR_SceneQucikPreviewEW.PrintError(e.Message);
     }
     PXR_SceneQucikPreviewEW.PrintSuccess("Deleted Cache Bundles.");
 }
    public static bool RestartApp()
    {
        if (!PXR_ADBTool.GetInstance().IsReady())
        {
            return(false);
        }

        string output, error;

        string[] appStartCommand = { "-d shell", "am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -S -f 0x10200000 -n", PXR_PathHelper.GetPlayerActivityName() };
        if (PXR_ADBTool.GetInstance().RunCommand(appStartCommand, null, out output, out error) == 0)
        {
            PXR_SceneQucikPreviewEW.PrintSuccess("App " + " Restart Success!");
            return(true);
        }

        string completeError = "Failed to restart App. Try restarting it manually through the device.\n" + (string.IsNullOrEmpty(error) ? output : error);

        Debug.LogError(completeError);
        return(false);
    }
    public static bool UninstallAPP()
    {
        PXR_SceneQucikPreviewEW.PrintLog("Uninstalling Application . . .");

        if (!PXR_ADBTool.GetInstance().IsReady())
        {
            return(false);
        }

        string output, error;
        string appPackagename = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.Android);

        string[] appStartCommand = { "-d shell", "pm uninstall", appPackagename };
        if (PXR_ADBTool.GetInstance().RunCommand(appStartCommand, null, out output, out error) == 0)
        {
            PXR_SceneQucikPreviewEW.PrintSuccess("App package " + appPackagename + " is uninstalled.");
            return(true);
        }

        PXR_SceneQucikPreviewEW.PrintError("Failed to uninstall APK.");
        return(false);
    }
    public static void BuildScenes(bool forceRestart)
    {
        if (!PXR_ADBTool.GetInstance().IsReady())
        {
            return;
        }

        if (!IsInstalledAPP())
        {
            InstallAPP();
        }

        GetScenesEnabled();

        remoteSceneCache = EXTERNAL_STORAGE_PATH + "/" + PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.Android)
                           + "/cache/scenes";

        Dictionary <string, string>         assetInSceneBundle = new Dictionary <string, string>();
        List <AssetBundleBuild>             assetBundleBuilds  = new List <AssetBundleBuild>();
        Dictionary <string, List <string> > extToAssetList     = new Dictionary <string, List <string> >();

        string[] resDirectories = Directory.GetDirectories("Assets", "Resources", SearchOption.AllDirectories).ToArray();

        if (resDirectories.Length > 0)
        {
            string[] resAssetPaths = AssetDatabase.FindAssets("", resDirectories).Select(x => AssetDatabase.GUIDToAssetPath(x)).ToArray();
            ProcessAssets(resAssetPaths, "resources", ref assetInSceneBundle, ref extToAssetList);

            AssetBundleBuild resBundle = new AssetBundleBuild();
            resBundle.assetNames      = assetInSceneBundle.Keys.ToArray();
            resBundle.assetBundleName = PXR_SQPLoader.RESOURCE_BUNDLE_NAME;
            assetBundleBuilds.Add(resBundle);
        }

        foreach (var scene in buildSceneInfoList)
        {
            string[] assetDependencies = AssetDatabase.GetDependencies(scene.scenePath);
            ProcessAssets(assetDependencies, scene.sceneName, ref assetInSceneBundle, ref extToAssetList);

            string[] sceneAsset = new string[1] {
                scene.scenePath
            };
            AssetBundleBuild sceneBuild = new AssetBundleBuild();
            sceneBuild.assetBundleName = "scene_" + scene.sceneName;
            sceneBuild.assetNames      = sceneAsset;
            assetBundleBuilds.Add(sceneBuild);
        }

        foreach (string ext in extToAssetList.Keys)
        {
            int assetCount = extToAssetList[ext].Count;
            int numChunks  = (assetCount + BUNDLE_CHUNK_SIZE - 1) / BUNDLE_CHUNK_SIZE;
            for (int i = 0; i < numChunks; i++)
            {
                List <string> assetChunkList;
                if (i == numChunks - 1)
                {
                    int size = BUNDLE_CHUNK_SIZE - (numChunks * BUNDLE_CHUNK_SIZE - assetCount);
                    assetChunkList = extToAssetList[ext].GetRange(i * BUNDLE_CHUNK_SIZE, size);
                }
                else
                {
                    assetChunkList = extToAssetList[ext].GetRange(i * BUNDLE_CHUNK_SIZE, BUNDLE_CHUNK_SIZE);
                }
                AssetBundleBuild build = new AssetBundleBuild();
                build.assetBundleName = "asset_" + ext + i;
                build.assetNames      = assetChunkList.ToArray();
                assetBundleBuilds.Add(build);
            }
        }

        // Build asset bundles
        BuildPipeline.BuildAssetBundles(PXR_DirectorySyncer.CreateDirectory(SQP_BUNDLE_PATH, SQP_SCENE_BUNDLE), assetBundleBuilds.ToArray(),
                                        BuildAssetBundleOptions.UncompressedAssetBundle, BuildTarget.Android);

        string tempDirectory = PXR_DirectorySyncer.CreateDirectory(SQP_BUNDLE_PATH, "Temp");

        string absoluteTempPath = Path.Combine(Path.Combine(Application.dataPath, ".."), tempDirectory);

        if (!PullSceneBundles(absoluteTempPath, remoteSceneCache))
        {
            return;
        }

        // Create file to tell SQP index scene APP which scene to load and push it to the device
        string sceneLoadDataPath = Path.Combine(tempDirectory, SCENE_LOAD_DATA_NAME);

        if (File.Exists(sceneLoadDataPath))
        {
            File.Delete(sceneLoadDataPath);
        }

        StreamWriter writer = new StreamWriter(sceneLoadDataPath, true);
        // Write version and scene names
        long unixTime = (int)(DateTimeOffset.UtcNow.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;

        writer.WriteLine(unixTime.ToString());
        for (int i = 0; i < buildSceneInfoList.Count; i++)
        {
            writer.WriteLine(Path.GetFileNameWithoutExtension(buildSceneInfoList[i].scenePath));
        }

        writer.Close();

        string absoluteSceneLoadDataPath = Path.Combine(absoluteTempPath, SCENE_LOAD_DATA_NAME);

        string[] pushCommand = { "-d push", "\"" + absoluteSceneLoadDataPath + "\"", "\"" + remoteSceneCache + "\"" };
        string   output, error;

        if (PXR_ADBTool.GetInstance().RunCommand(pushCommand, null, out output, out error) != 0)
        {
            PXR_SceneQucikPreviewEW.PrintError(string.IsNullOrEmpty(error) ? output : error);
            return;
        }

        if (forceRestart)
        {
            RestartApp();
            return;
        }

        PXR_SceneQucikPreviewEW.PrintSuccess("Build Scenes.");
    }
    private static bool PullSceneBundles(string absoluteTempPath, string externalSceneCache)
    {
        List <string> bundlesToTransfer = new List <string>();
        string        manifestFilePath  = externalSceneCache + "/" + SQP_SCENE_BUNDLE;

        string[] pullManifestCommand = { "-d pull", "\"" + manifestFilePath + "\"", "\"" + absoluteTempPath + "\"" };

        string output, error;

        if (PXR_ADBTool.GetInstance().RunCommand(pullManifestCommand, null, out output, out error) == 0)
        {
            // Load hashes from remote manifest
            AssetBundle remoteBundle = AssetBundle.LoadFromFile(Path.Combine(absoluteTempPath, SQP_SCENE_BUNDLE));
            if (remoteBundle == null)
            {
                PXR_SceneQucikPreviewEW.PrintError("Failed to load remote asset bundle manifest file.");
                return(false);
            }
            AssetBundleManifest remoteManifest = remoteBundle.LoadAsset <AssetBundleManifest>("AssetBundleManifest");

            Dictionary <string, Hash128> remoteBundleToHash = new Dictionary <string, Hash128>();
            if (remoteManifest != null)
            {
                string[] assetBundles = remoteManifest.GetAllAssetBundles();
                foreach (string bundleName in assetBundles)
                {
                    remoteBundleToHash[bundleName] = remoteManifest.GetAssetBundleHash(bundleName);
                }
            }
            remoteBundle.Unload(true);

            AssetBundle localBundle = AssetBundle.LoadFromFile(SQP_BUNDLE_PATH + "\\" + SQP_SCENE_BUNDLE
                                                               + "\\" + SQP_SCENE_BUNDLE);
            if (localBundle == null)
            {
                PXR_SceneQucikPreviewEW.PrintError("Failed to load local asset bundle manifest file.");
                return(false);
            }
            AssetBundleManifest localManifest = localBundle.LoadAsset <AssetBundleManifest>("AssetBundleManifest");

            if (localManifest != null)
            {
                Hash128 zeroHash = new Hash128(0, 0, 0, 0);

                // Build a list of dirty bundles that will have to be transfered
                string relativeSceneBundlesPath = Path.Combine(SQP_BUNDLE_PATH, SQP_SCENE_BUNDLE);
                bundlesToTransfer.Add(Path.Combine(relativeSceneBundlesPath, SQP_SCENE_BUNDLE));
                string[] assetBundles = localManifest.GetAllAssetBundles();
                foreach (string bundleName in assetBundles)
                {
                    if (!remoteBundleToHash.ContainsKey(bundleName))
                    {
                        bundlesToTransfer.Add(Path.Combine(relativeSceneBundlesPath, bundleName));
                    }
                    else
                    {
                        if (remoteBundleToHash[bundleName] != localManifest.GetAssetBundleHash(bundleName))
                        {
                            bundlesToTransfer.Add(Path.Combine(relativeSceneBundlesPath, bundleName));
                        }
                        remoteBundleToHash[bundleName] = zeroHash;
                    }
                }

                PXR_SceneQucikPreviewEW.PrintLog(bundlesToTransfer.Count + " dirty bundle(s) will be transfered.\n");
            }
        }
        else
        {
            if (output.Contains("does not exist") || output.Contains("No such file or directory"))
            {
                PXR_SceneQucikPreviewEW.PrintLog("Manifest file not found. Transfering all bundles . . . ");

                string[] mkdirCommand = { "-d shell", "mkdir -p", "\"" + externalSceneCache + "\"" };
                if (PXR_ADBTool.GetInstance().RunCommand(mkdirCommand, null, out output, out error) == 0)
                {
                    string absoluteSceneBundlePath = Path.Combine(Path.Combine(Application.dataPath, ".."),
                                                                  Path.Combine(SQP_BUNDLE_PATH, SQP_SCENE_BUNDLE));

                    string[] assetBundlePaths = Directory.GetFiles(absoluteSceneBundlePath);
                    if (assetBundlePaths.Length == 0)
                    {
                        PXR_SceneQucikPreviewEW.PrintError("Failed to locate scene bundles to transfer.");
                        return(false);
                    }
                    foreach (string path in assetBundlePaths)
                    {
                        if (!path.Contains(".manifest"))
                        {
                            bundlesToTransfer.Add(path);
                        }
                    }
                }
            }
        }

        if (!string.IsNullOrEmpty(error) || output.Contains("error"))
        {
            PXR_SceneQucikPreviewEW.PrintError(string.IsNullOrEmpty(error) ? output : error);
            return(false);
        }

        foreach (string bundle in bundlesToTransfer)
        {
            string   absoluteBundlePath = Path.Combine(Path.Combine(Application.dataPath, ".."), bundle);
            string[] pushBundleCommand  = { "-d push", "\"" + absoluteBundlePath + "\"", "\"" + externalSceneCache + "\"" };
            PXR_ADBTool.GetInstance().RunCommandAsync(pushBundleCommand, null);
        }

        return(true);
    }