private async Task ReportAppStatus(AppxManagementDataContract.AppReportedState appReportedState)
        {
            JObject reportedStateObject = appReportedState.ToJsonObject();

            Logger.Log("Report:\n" + reportedStateObject.ToString(), LoggingLevel.Verbose);
            await this._callback.ReportPropertiesAsync(PropertySectionName, reportedStateObject);
        }
        private async Task UninstallAppAsync(AppInfo appInfo, string packageFamilyId, string packageFamilyName)
        {
            Logger.Log("Processing uninstall request...", LoggingLevel.Verbose);

            AppxManagementDataContract.AppReportedState reportedState = null;
            try
            {
                Windows.ApplicationModel.PackageId thisPackage = Windows.ApplicationModel.Package.Current.Id;
                Debug.WriteLine("FamilyName = " + thisPackage.FamilyName);
                Debug.WriteLine("Name       = " + thisPackage.Name);

                if (packageFamilyName == thisPackage.FamilyName)
                {
                    throw new Error(ErrorCodes.CANNOT_UNINSTALL_DM_APPLICATION, "Cannot uninstall the DM application: " + thisPackage.FamilyName);
                }

                // ToDo: We need to handle store and system apps too.
                AppUninstallResponse response = await UninstallAppAsync(new AppUninstallRequestData(packageFamilyName, false /*non-store app*/));

                reportedState = new AppxManagementDataContract.AppReportedState(packageFamilyId,
                                                                                packageFamilyName,
                                                                                AppxManagementDataContract.VersionNotInstalled,
                                                                                AppxStartUpType.None,
                                                                                null, // no install date
                                                                                0,    // no error
                                                                                null,
                                                                                JsonReport.Report);
                _stateToReport[packageFamilyId] = reportedState;
                return;
            }
            catch (Error e)
            {
                reportedState = new AppxManagementDataContract.AppReportedState(packageFamilyId,
                                                                                packageFamilyName,
                                                                                appInfo.Version,
                                                                                AppUtils.StartUpTypeFromMessage(appInfo.StartUp),
                                                                                appInfo.InstallDate,
                                                                                e.HResult,
                                                                                e.Message,
                                                                                JsonReport.Report);
            }
            catch (Exception e)
            {
                reportedState = new AppxManagementDataContract.AppReportedState(packageFamilyId,
                                                                                packageFamilyName,
                                                                                appInfo.Version,
                                                                                AppUtils.StartUpTypeFromMessage(appInfo.StartUp),
                                                                                appInfo.InstallDate,
                                                                                e.HResult,
                                                                                e.Message,
                                                                                JsonReport.Report);
            }
            _stateToReport[packageFamilyId] = reportedState;
            throw new Exception("Failed to uninstall " + packageFamilyName);
        }
        private static void ProcessFullListQuery(
            IDictionary <string, AppInfo> installedApps,
            AppxManagementDataContract.AppListQuery appListQuery,
            Dictionary <string, AppxManagementDataContract.AppReportedState> stateToReport
            )
        {
            // Process the "?"
            if (!appListQuery.nonStore && !appListQuery.store)
            {
                // There's nothing to do...
                return;
            }

            foreach (var pair in installedApps)
            {
                AppxManagementDataContract.AppReportedState dummyAppReportedState;
                if (stateToReport.TryGetValue(pair.Value.PackageFamilyName, out dummyAppReportedState))
                {
                    // Already queued to be reported, no need to consider adding it to stateToReport.
                    continue;
                }
                if ((pair.Value.AppSource == AppxManagementDataContract.JsonAppSourceStore && appListQuery.store) ||
                    (pair.Value.AppSource == AppxManagementDataContract.JsonappSourceNonStore && appListQuery.nonStore))
                {
                    AppxManagementDataContract.AppReportedState appReportedState = new AppxManagementDataContract.AppReportedState(
                        pair.Value.PackageFamilyName.Replace('.', '_'),
                        pair.Value.PackageFamilyName,
                        pair.Value.Version,
                        AppUtils.StartUpTypeFromMessage(pair.Value.StartUp),
                        pair.Value.InstallDate,
                        0,
                        null,
                        JsonReport.Report);

                    stateToReport[pair.Value.PackageFamilyName] = appReportedState;
                }
            }
        }
        private static void ReportQueriedApp(
            AppInfo installedAppInfo,
            AppxManagementDataContract.AppDesiredState desiredState,
            Dictionary <string, AppxManagementDataContract.AppReportedState> stateToReport)
        {
            Logger.Log("Processing query request...", LoggingLevel.Verbose);

            AppxManagementDataContract.AppReportedState appReportedState;
            if (installedAppInfo == null)
            {
                Logger.Log("    Couldn't find an installed version...", LoggingLevel.Verbose);

                appReportedState = new AppxManagementDataContract.AppReportedState(
                    desiredState.packageFamilyId,
                    desiredState.packageFamilyName,
                    AppxManagementDataContract.VersionNotInstalled,
                    AppUtils.StartUpTypeFromMessage(StartUpType.None),
                    null,
                    0,
                    null,
                    JsonReport.Report);
            }
            else
            {
                Logger.Log("    Found an installed version...", LoggingLevel.Verbose);

                appReportedState = new AppxManagementDataContract.AppReportedState(
                    desiredState.packageFamilyId,
                    desiredState.packageFamilyName,
                    installedAppInfo.Version,
                    AppUtils.StartUpTypeFromMessage(installedAppInfo.StartUp),
                    installedAppInfo.InstallDate,
                    0,
                    null,
                    JsonReport.Report);
            }
            stateToReport[desiredState.packageFamilyId] = appReportedState;
        }
        private async Task <CommandStatus> ApplyAppDesiredState(string connectionString, IDictionary <string, AppInfo> installedApps, AppxManagementDataContract.AppDesiredState desiredState)
        {
            CommandStatus commandStatus       = CommandStatus.NotStarted;
            Version       installedAppVersion = null;
            AppInfo       installedAppInfo    = FindInstalledAppInfo(installedApps, desiredState.packageFamilyName);

            if (installedAppInfo != null)
            {
                installedAppVersion = new Version(installedAppInfo.Version);
            }

            switch (desiredState.action)
            {
            case AppDesiredAction.Install:
            {
                commandStatus = await InstallAppAsync(installedAppInfo, installedAppVersion, connectionString, installedApps, desiredState);
            }
            break;

            case AppDesiredAction.Uninstall:
            {
                await UninstallAppAsync(installedAppInfo,
                                        packageFamilyId : desiredState.packageFamilyId,
                                        packageFamilyName : desiredState.packageFamilyName);
            }
            break;

            case AppDesiredAction.Query:
            {
                ReportQueriedApp(installedAppInfo, desiredState, _stateToReport);
            }
            break;

            case AppDesiredAction.Unreport:
            {
                Logger.Log("Processing unreport request...", LoggingLevel.Verbose);

                AppxManagementDataContract.AppReportedState appReportedState = new AppxManagementDataContract.AppReportedState(
                    desiredState.packageFamilyId,
                    desiredState.packageFamilyName,
                    null,           // no version
                    AppUtils.StartUpTypeFromMessage(StartUpType.None),
                    null,           // no install date
                    0,
                    null,           // no error
                    JsonReport.Unreport);

                _stateToReport[desiredState.packageFamilyId] = appReportedState;
            }
            break;

            case AppDesiredAction.Undefined:
            {
                Logger.Log("Processing unknown request...", LoggingLevel.Verbose);

                AppxManagementDataContract.AppReportedState appReportedState = new AppxManagementDataContract.AppReportedState(
                    desiredState.packageFamilyId,
                    desiredState.packageFamilyName,
                    null,           // no version
                    AppUtils.StartUpTypeFromMessage(StartUpType.None),
                    null,           // no install date
                    ErrorCodes.INVALID_DESIRED_APPX_OPERATION,
                    "Invalid application operation.",
                    JsonReport.Report);

                _stateToReport[desiredState.packageFamilyId] = appReportedState;
            }
            break;
            }

            return(commandStatus);
        }
        private async Task <CommandStatus> InstallAppAsync(
            AppInfo installedAppInfo,
            Version installedAppVersion,
            string connectionString,
            IDictionary <string, AppInfo> installedApps,
            AppxManagementDataContract.AppDesiredState desiredState)
        {
            Logger.Log("Processing install request for " + desiredState.packageFamilyId, LoggingLevel.Verbose);

            if (installedAppInfo == null)
            {
                // It is a new application.
                Logger.Log("    Can't find an installed version... Installing a fresh copy...", LoggingLevel.Verbose);
                await InstallAppFromAzureAsync(installedAppInfo, connectionString, desiredState, false /*not self update*/);       // ---> InstallAppFromAzureAsync
            }
            else
            {
                Windows.ApplicationModel.PackageId thisPackage = Windows.ApplicationModel.Package.Current.Id;
                Debug.WriteLine("FamilyName = " + thisPackage.FamilyName);
                Debug.WriteLine("Name       = " + thisPackage.Name);

                bool isSelf = desiredState.packageFamilyName == thisPackage.FamilyName;

                // A version of this application is installed.
                Logger.Log("    Found an installed version...", LoggingLevel.Verbose);

                if (desiredState.version == installedAppVersion)
                {
                    Logger.Log("        Same version is installed...", LoggingLevel.Verbose);
                    AppxManagementDataContract.AppReportedState appReportedState = null;

                    if (AppUtils.StartUpTypeToMessage(desiredState.startUp) == installedAppInfo.StartUp)
                    {
                        Logger.Log("        App StartUp is the same: desired = " + desiredState.startUp, LoggingLevel.Verbose);

                        appReportedState = new AppxManagementDataContract.AppReportedState(
                            desiredState.packageFamilyId,
                            desiredState.packageFamilyName,
                            installedAppVersion.ToString(),
                            AppUtils.StartUpTypeFromMessage(installedAppInfo.StartUp),
                            installedAppInfo.InstallDate,
                            0,
                            null,                 // no error
                            JsonReport.Report);
                    }
                    else
                    {
                        Logger.Log("        App StartUp is different: desired = " + desiredState.startUp.ToString() + ", current = " + installedAppInfo.StartUp.ToString(), LoggingLevel.Verbose);

                        switch (desiredState.startUp)
                        {
                        case AppxStartUpType.None:
                        {
                            bool background = installedAppInfo.StartUp == StartUpType.Background;
                            if (background)
                            {
                                Logger.Log("            Removing app from background apps.", LoggingLevel.Verbose);
                                StartupAppInfo startupAppInfo = new StartupAppInfo(desiredState.packageFamilyName, background);
                                await RemoveStartupAppAsync(startupAppInfo);
                            }
                            else
                            {
                                Logger.Log("            App is no longer marked to be start-up app. Change takes effect when another app is set to be the start-up app.", LoggingLevel.Verbose);
                            }
                        }
                        break;

                        case AppxStartUpType.Foreground:
                        {
                            Logger.Log("            Setting app to be the foreground app.", LoggingLevel.Verbose);
                            StartupAppInfo startupAppInfo = new StartupAppInfo(desiredState.packageFamilyName, false /*background*/);
                            await AddStartupAppAsync(startupAppInfo);
                        }
                        break;

                        case AppxStartUpType.Background:
                        {
                            Logger.Log("            Adding app to the background apps.", LoggingLevel.Verbose);
                            StartupAppInfo startupAppInfo = new StartupAppInfo(desiredState.packageFamilyName, true /*background*/);
                            await AddStartupAppAsync(startupAppInfo);
                        }
                        break;
                        }

                        AppxStartUpType appStartUp = await GetAppStartup(desiredState.packageFamilyName);

                        Logger.Log("            Querying returned app startup: " + appStartUp.ToString(), LoggingLevel.Verbose);

                        appReportedState = new AppxManagementDataContract.AppReportedState(
                            desiredState.packageFamilyId,
                            desiredState.packageFamilyName,
                            installedAppVersion.ToString(),
                            appStartUp,
                            installedAppInfo.InstallDate,
                            0,
                            null,                 // no error
                            JsonReport.Report);
                    }

                    _stateToReport[desiredState.packageFamilyId] = appReportedState;
                }
                else if (desiredState.version > installedAppVersion)
                {
                    Logger.Log("        Older version is installed...", LoggingLevel.Verbose);

                    if (!String.IsNullOrEmpty(desiredState.appxSource))
                    {
                        // Trigger the update...
                        await InstallAppFromAzureAsync(installedAppInfo, connectionString, desiredState, isSelf);

                        if (isSelf)
                        {
                            // If isSelf == true, it means that SystemConfigurator will force this application to exit very soon.
                            // Let's stop processing any further desired properties.
                            return(CommandStatus.PendingDMAppRestart);
                        }
                    }
                    else
                    {
                        // Note that store updates are not control through DM desired properties.
                        // Instead, they are triggered by the system scan for all store applications.
                        throw new Error(ErrorCodes.INVALID_DESIRED_APPX_SRC, "Appx package is required to update " + desiredState.packageFamilyName);
                    }
                }
                else
                {
                    // desiredState.version < installedAppVersion
                    Logger.Log("       Newer version is installed...rolling back.", LoggingLevel.Verbose);

                    if (String.IsNullOrEmpty(desiredState.appxSource))
                    {
                        AppxManagementDataContract.AppReportedState appReportedState = new AppxManagementDataContract.AppReportedState(
                            desiredState.packageFamilyId,
                            desiredState.packageFamilyName,
                            installedAppVersion.ToString(),
                            AppUtils.StartUpTypeFromMessage(installedAppInfo.StartUp),
                            installedAppInfo.InstallDate,
                            ErrorCodes.INVALID_DESIRED_APPX_SRC,
                            "Cannot install appx without a source.",
                            JsonReport.Report);

                        _stateToReport[desiredState.packageFamilyId] = appReportedState;

                        throw new Exception("Failed to roll back application version.");
                    }

                    if (isSelf)
                    {
                        // The reverting is implemented as an 'uninstall' followed by an 'install'.
                        // The package to be installed is downloaded in the 'install' step.
                        // So, if we were to revert self to an older version, we would have to:
                        //  - (1) download the old version first,
                        //  - (2) send an atomic uninstall-install request to SystemConfigurator to
                        //        uninstall and follow with an install and re-launch.
                        //  The above two steps are not implemented yet.
                        throw new Error(ErrorCodes.CANNOT_REVERT_DM_APPLICATION, "Reverting to an older version of the device management application (" + desiredState.packageFamilyName + ") is not supported.");
                    }
                    // Note that UninstallAppAsync will throw if it fails - and correctly avoid launching the install...
                    await UninstallAppAsync(installedAppInfo,
                                            packageFamilyId : desiredState.packageFamilyId,
                                            packageFamilyName : desiredState.packageFamilyName);
                    await InstallAppFromAzureAsync(installedAppInfo, connectionString, desiredState, isSelf);
                }
            }

            return(CommandStatus.Committed);
        }
        private async Task InstallAppFromAzureAsync(AppInfo currentState, string connectionString, AppxManagementDataContract.AppDesiredState desiredState, bool selfUpdate)
        {
            // Is this a fresh installation?
            if (currentState == null)
            {
                currentState = new AppInfo();
                currentState.PackageFamilyName = desiredState.packageFamilyName;
                currentState.Version           = AppxManagementDataContract.VersionNotInstalled;
                currentState.InstallDate       = "";
            }

            AppxManagementDataContract.AppReportedState reportedState = null;
            try
            {
                Logger.Log("-> installing " + desiredState.packageFamilyName + " from " + desiredState.appxSource, LoggingLevel.Verbose);
                if (String.IsNullOrEmpty(desiredState.appxSource))
                {
                    throw new Error(ErrorCodes.INVALID_DESIRED_APPX_SRC, "Cannot install appx without a source.");
                }

                var requestData = new AppInstallRequestData();
                requestData.PackageFamilyName = desiredState.packageFamilyName;
                requestData.StartUp           = AppUtils.StartUpTypeToMessage(desiredState.startUp);

                // Downloading dependencies...
                Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Downloading...", LoggingLevel.Verbose);
                if (!String.IsNullOrEmpty(desiredState.depsSources))
                {
                    string[] depsSources = desiredState.depsSources.Split(';');

                    for (int i = 0; i < depsSources.Length; ++i)
                    {
                        IoTDMClient.BlobInfo dependencyBlob = IoTDMClient.BlobInfo.BlobInfoFromSource(connectionString, depsSources[i]);
                        Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Downloading " + dependencyBlob.BlobName, LoggingLevel.Verbose);

                        var dependencyPath = await dependencyBlob.DownloadToTempAsync(this._systemConfiguratorProxy);

                        Logger.Log(dependencyPath, LoggingLevel.Verbose);
                        requestData.Dependencies.Add(dependencyPath);
                    }
                }

                // Downloading certificates...
                Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Downloading appx certificate...", LoggingLevel.Verbose);
                IoTDMClient.BlobInfo certificateBlob = IoTDMClient.BlobInfo.BlobInfoFromSource(connectionString, desiredState.certSource);
                requestData.CertFile = await certificateBlob.DownloadToTempAsync(this._systemConfiguratorProxy);

                requestData.CertStore = desiredState.certStore;

                // Downloading appx...
                Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Downloading appx...", LoggingLevel.Verbose);
                IoTDMClient.BlobInfo appxBlob = IoTDMClient.BlobInfo.BlobInfoFromSource(connectionString, desiredState.appxSource);
                requestData.AppxPath = await appxBlob.DownloadToTempAsync(this._systemConfiguratorProxy);

                requestData.IsDMSelfUpdate = selfUpdate;

                // Installing appx...
                Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Installing appx...", LoggingLevel.Verbose);
                AppInstallResponse response = await InstallAppAsync(requestData);

                if (response.data.pending)
                {
                    Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Installing appx is pending...", LoggingLevel.Verbose);
                    Debug.Assert(selfUpdate);

                    reportedState = new AppxManagementDataContract.AppReportedState(desiredState.packageFamilyId,
                                                                                    desiredState.packageFamilyName,
                                                                                    CommonDataContract.JsonPending,
                                                                                    AppUtils.StartUpTypeFromMessage(response.data.startUp),
                                                                                    response.data.installDate,
                                                                                    0,
                                                                                    null,
                                                                                    JsonReport.Report);
                    _stateToReport[desiredState.packageFamilyId] = reportedState;
                    return;
                }
                else
                {
                    Logger.Log(DateTime.Now.ToString("HH:mm:ss") + " Done installing appx...", LoggingLevel.Verbose);

                    Error e = null;
                    if (desiredState.version.ToString() != response.data.version)
                    {
                        if (currentState.Version == response.data.version)
                        {
                            e = new Error(ErrorCodes.INVALID_INSTALLED_APP_VERSION_UNCHANGED, "Installating the supplied appx succeeded, but the new app version is not the desired version, and is the same as the old app version.");
                        }
                        else
                        {
                            e = new Error(ErrorCodes.INVALID_INSTALLED_APP_VERSION_UNEXPECTED, "Installating the supplied appx succeeded, but the new app version is not the desired version.");
                        }
                    }

                    reportedState = new AppxManagementDataContract.AppReportedState(desiredState.packageFamilyId,
                                                                                    desiredState.packageFamilyName,
                                                                                    response.data.version,
                                                                                    AppUtils.StartUpTypeFromMessage(response.data.startUp),
                                                                                    response.data.installDate,
                                                                                    (e != null? e.HResult : 0),
                                                                                    (e != null ? e.Message : null),
                                                                                    JsonReport.Report);
                    _stateToReport[desiredState.packageFamilyId] = reportedState;
                    return;
                }
            }
            catch (Error e)
            {
                reportedState = new AppxManagementDataContract.AppReportedState(desiredState.packageFamilyId,
                                                                                desiredState.packageFamilyName,
                                                                                currentState.Version,
                                                                                AppUtils.StartUpTypeFromMessage(currentState.StartUp),
                                                                                currentState.InstallDate, // install date
                                                                                e.HResult,
                                                                                e.Message,
                                                                                JsonReport.Report);
            }
            catch (Exception e)
            {
                reportedState = new AppxManagementDataContract.AppReportedState(desiredState.packageFamilyId,
                                                                                desiredState.packageFamilyName,
                                                                                currentState.Version,
                                                                                AppUtils.StartUpTypeFromMessage(currentState.StartUp),
                                                                                currentState.InstallDate, // install date
                                                                                e.HResult,
                                                                                e.Message,
                                                                                JsonReport.Report);
            }
            _stateToReport[desiredState.packageFamilyId] = reportedState;
            throw new Exception("Failed to install " + desiredState.packageFamilyName);
        }