Example #1
0
        /// <summary>
        /// Helper method to download assets asynchronously. After completion, scene is automatically reloaded
        /// if new assets have been downloaded.
        /// </summary>
        /// <param name="config">Current config</param>
        /// <param name="downloadProgress">Download progress interface - used to indicate download progress</param>
        /// <returns></returns>
        public static async Task DownloadAssetsAsync(Config config, IDownloadProgress downloadProgress = null, bool forceCheck = false)
        {
            // Start background thread
            Task.Run(async() =>
            {
                // Mutual exclusion while loading assets
                await AssetsDownloader.semaphoreSlim.WaitAsync();

                // Attach / detatch JNI. Required for any calls into JNI from background threads.
                AndroidJNI.AttachCurrentThread();

                try
                {
                    // Download assets from repos.
                    AssetsDownloader assetsDownloader = new AssetsDownloader();
                    return(await assetsDownloader.DownloadFromReposAsync(config, downloadProgress, forceCheck));
                }
                finally
                {
                    AssetsDownloader.semaphoreSlim.Release();
                    AndroidJNI.DetachCurrentThread();
                }
            }).ContinueWith((downloadedAssets) =>
            {
                if (downloadedAssets.Result)
                {
                    // We downloaded new assets, so re-load the scene
                    Debug.Log("Downloaded new assets. Re-populating panel");
                    SceneManager.LoadSceneAsync(SceneManager.GetActiveScene().name);
                }
            });
        }
        /// <summary>
        /// Opens the rename dialog
        /// </summary>
        /// <param name="entry"></param>
        public async void Rename(AppEntry appTarget)
        {
            Debug.Assert(null != this.appToRename, "App to rename is null");
            var  filePath    = appTarget.externalIconPath;
            bool cleanupFile = false;

            // If icon path is null, extract icon from apk
            if (null == filePath)
            {
                filePath    = Path.Combine(AssetsDownloader.GetOrCreateDownloadPath(), this.appToRename.packageId + ".jpg");
                cleanupFile = true;

                var bytes = appTarget.sprite.GetComponent <Image>().sprite.texture.EncodeToJPG();
                using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None,
                                                       bufferSize: 4096, useAsync: true))
                {
                    await fileStream.WriteAsync(bytes, 0, bytes.Length);
                };
            }

            await Task.Run(() =>
            {
                AndroidJNI.AttachCurrentThread();

                try
                {
                    // Add to json file
                    AddToRenameJsonFile(this.appToRename.packageId, appTarget.appName);

                    // Add icon to zip
                    using (AndroidJavaClass unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
                        using (AndroidJavaObject currentActivity = unity.GetStatic <AndroidJavaObject>("currentActivity"))
                        {
                            var renameIconPackFilePath = Path.Combine(UnityEngine.Application.persistentDataPath, AppProcessor.RenameIconPackFileName);
                            currentActivity.CallStatic("addFileToZip", renameIconPackFilePath, filePath, this.appToRename.packageId + ".jpg");
                        }
                }
                finally
                {
                    AndroidJNI.DetachCurrentThread();
                }
            });

            if (cleanupFile && File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            // Reload the scene
            await SceneManager.LoadSceneAsync(SceneManager.GetActiveScene().name);
        }
        /// <summary>
        /// Populate the grid from installed apps
        /// </summary>
        /// <returns></returns>
        private async Task PopulateAsync(bool isRenameMode = false)
        {
            // Load configuration
            var config = ConfigPersistence.LoadConfig();

            // Set skybox
            if (!isRenameMode)
            {
                this.skyboxHandler.SetSkybox(config.background);
            }

            // Process apps in background
            var apps = await Task.Run(() =>
            {
                AndroidJNI.AttachCurrentThread();

                try
                {
                    return(AppProcessor.ProcessApps(config, isRenameMode));
                }
                finally
                {
                    AndroidJNI.DetachCurrentThread();
                }
            });

            // Download updates in the background
            if (!isRenameMode && config.autoUpdate && !GlobalState.Instance.CheckedForUpdate)
            {
                GlobalState.Instance.CheckedForUpdate = true;
                AssetsDownloader.DownloadAssetsAsync(config, this.downloadStatusIndicator);
            }

            // Populate the panel content
            if (!isRenameMode)
            {
                await PopulatePanelContentAsync(config, apps);
            }
            else
            {
                await PopulateRenamePanelContentAsync(config, apps);
            }
        }
        /// <summary>
        /// Entry point for app processing: Applies app name overrides (from appnames.txt/json) and app icons (from individual jpgs or icon packs).
        /// Handles extraction of icon packs if zip file modified. Returns a list of processed apps.
        /// </summary>
        /// <param name="config">Application config</param>
        /// <param name="isRenameMode">Whether in rename mode. If so, returns all apps found, not just installed ones.</param>
        /// <returns>Dictionary of processed apps</returns>
        public static Dictionary <string, ProcessedApp> ProcessApps(Config config, bool isRenameMode = false)
        {
            var persistentDataPath = UnityEngine.Application.persistentDataPath;

            Debug.Log("Persistent data path: " + persistentDataPath);

            // Dictionary to hold package name -> app index, app name
            var apps = new Dictionary <string, ProcessedApp>(StringComparer.OrdinalIgnoreCase);
            var excludedPackageNames = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            using (AndroidJavaClass unity = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
                using (AndroidJavaObject currentActivity = unity.GetStatic <AndroidJavaObject>("currentActivity"))
                {
                    // Get # of installed apps
                    int numApps = currentActivity.Call <int>("getSize");
                    Debug.Log("# installed apps: " + numApps);

                    var processedLastTimeUsed = false;
                    if (config.sortMode.Equals(Config.Sort_MostRecent, StringComparison.OrdinalIgnoreCase))
                    {
                        // Process last time used for each app
                        currentActivity.Call("processLastTimeUsed", LastUsedLookbackDays);
                        processedLastTimeUsed = true;
                    }

                    if (!isRenameMode)
                    {
                        // Add current package name to excludedPackageNames to filter it out
                        excludedPackageNames.Add(currentActivity.Call <string>("getPackageName"));
                    }

                    // This is a file containing packageNames that will be excluded.
                    // Skip this if in rename mode.
                    var excludedPackageNamesFilePath = Path.Combine(persistentDataPath, ExcludedPackagesFile);
                    if (!isRenameMode && File.Exists(excludedPackageNamesFilePath))
                    {
                        Debug.Log("Found file: " + excludedPackageNamesFilePath);
                        string[] excludedPackages = File.ReadAllLines(excludedPackageNamesFilePath);
                        foreach (string excludedPackage in excludedPackages)
                        {
                            if (!string.IsNullOrEmpty(excludedPackage))
                            {
                                excludedPackageNames.Add(excludedPackage);
                            }
                        }
                    }

                    // Get installed package and app names
                    for (int i = 0; i < numApps; i++)
                    {
                        var packageName  = currentActivity.Call <string>("getPackageName", i);
                        var appName      = currentActivity.Call <string>("getAppName", i);
                        var lastTimeUsed = processedLastTimeUsed ? currentActivity.Call <long>("getLastTimeUsed", i) : 0;

                        if (excludedPackageNames.Contains(packageName))
                        {
                            // Skip excluded package
                            Debug.LogFormat("Skipping Excluded [{0}] Package: {1}, name: {2}", i, packageName, appName);
                            continue;
                        }

                        // Determine app type (Quest, Go or 2D)
                        string tabName;
                        if (currentActivity.Call <bool>("is2DApp", i))
                        {
                            if (!config.show2D)
                            {
                                // Skip 2D apps
                                Debug.LogFormat("Skipping 2D [{0}] Package: {1}, name: {2}", i, packageName, appName);
                                continue;
                            }

                            tabName = Tab_2D;
                        }
                        else if (currentActivity.Call <bool>("isQuestApp", i))
                        {
                            tabName = Tab_Quest;
                        }
                        else
                        {
                            tabName = Tab_Go;
                        }

                        apps.Add(packageName, new ProcessedApp {
                            PackageName = packageName, Index = i,
                            AutoTabName = tabName, AppName = appName, LastTimeUsed = lastTimeUsed
                        });
                        Debug.LogFormat("[{0}] package: {1}, name: {2}, auto tab: {3}", i, packageName, appName, tabName);
                    }

                    // Process app name overrides files (both downloaded & manually created)
                    ProcessAppNameOverrideFiles(isRenameMode, apps, AssetsDownloader.GetOrCreateDownloadPath());
                    ProcessAppNameOverrideFiles(isRenameMode, apps, persistentDataPath);

                    // Extract icon packs (both downloaded & manually created)
                    ExtractIconPacks(currentActivity, AssetsDownloader.GetOrCreateDownloadPath());
                    ExtractIconPacks(currentActivity, persistentDataPath);

                    // Process extracted icons (both downloaded & manually created)
                    ProcessExtractedIcons(isRenameMode, apps, AssetsDownloader.GetOrCreateDownloadPath());
                    ProcessExtractedIcons(isRenameMode, apps, persistentDataPath);

                    // Process any individual icons
                    var iconOverridePath = persistentDataPath;
                    if (Directory.Exists(persistentDataPath))
                    {
                        ProcessIconsInPath(apps, persistentDataPath);
                    }
                }

            return(apps);
        }
Example #5
0
 public void UpdateAssetsNow()
 {
     AssetsDownloader.DownloadAssetsAsync(config, this.downloadStatusIndicator, true);
 }