/// <summary> /// Because the app has registered to support "Photos" extension the agent will be invoked /// and requested to download the album items when the user taps on our tile /// in the photos hub. This method handles the operation by synchronizing the local /// store with our web server (Bing Images). /// </summary> /// <param name="operation">The operation that we need to perform</param> private async Task ProcessOperation(DownloadAlbumItemsOperation operation) { try { Logger.Log("Agent", "DownloadAlbumItemsOperation(" + operation.ParentAlbumId + ")"); if (string.IsNullOrEmpty(operation.ParentAlbumId)) { // An empty ParentAlbumId means that we need to populate the root album OnlinePictureAlbum rootAlbum = await manager.GetRootPictureAlbumAsync(); // Let's add the top level albums // Simulate server request to get the top level albums // (note: this code sample builds the list statically) List <BingApi.Album> topLevelAlbums = BingApi.GetAlbums(); foreach (BingApi.Album newAlbum in topLevelAlbums) { OnlinePictureAlbum album = await manager.GetPictureAlbumByRemoteIdAsync(newAlbum.id); if (null == album) { album = manager.CreatePictureAlbum(newAlbum.id, rootAlbum.Id); album.Title = newAlbum.title; // The albums that have the RequiresAuthentication flag set will // trigger a DownloadImageOperation every time the Photos app needs // to display an image that hasn't already been downloaded. album.RequiresAuthentication = newAlbum.authRequired; await manager.SavePictureAlbumAsync(album); } } } else { // ParentAlbumId is the remote id of the album that we need to populate OnlinePictureAlbum album = await manager.GetPictureAlbumByRemoteIdAsync(operation.ParentAlbumId); // Make a network call to get the most recent VersionStamp string newVersionStamp = await BingApi.GetVersionStampAsync(operation.ParentAlbumId); // Is up to the app to use the VersionStamp on the album to best suit its needs. // The OS doesn't use this value. The app can use it to determine if the album is // up to date. Only trigger a full sync if the album is not up to date. if (album.VersionStamp != newVersionStamp) { // Get all the pictures that are currently in the album OnlineMediaItemQueryResult query = album.GetContentsQuery(); IList <IOnlineMediaItem> oldPictures = await query.GetItemsAsync(); // Mark all current pictures for deletion Dictionary <string, OnlinePicture> photosToDelete = new Dictionary <string, OnlinePicture>(); foreach (IOnlineMediaItem item in oldPictures) { OnlinePicture onlinePicture = item as OnlinePicture; if (null != onlinePicture) { photosToDelete.Add(onlinePicture.RemoteId, onlinePicture); } } // Contact server to download the metadata for all the items in the album List <BingApi.Photo> newPhotos = await BingApi.GetAllPhotosMetadataAsync(operation.ParentAlbumId); // Fill with new photos List <OnlinePicture> photosToSave = new List <OnlinePicture>(); // Save a reference to the most recent photo among the new photos to use it as the cover for the album OnlinePicture mostRecent = null; foreach (BingApi.Photo newPhoto in newPhotos) { OnlinePicture onlinePicture = await manager.GetPictureByRemoteIdAsync(newPhoto.id); if (null == onlinePicture) { OnlinePicture localPhoto = manager.CreatePicture(newPhoto.id, album.Id); localPhoto.Title = newPhoto.title; localPhoto.CreationTime = newPhoto.timestamp; localPhoto.ThumbnailSmallUrl = new Uri(newPhoto.smallThumbnailUrl); // required localPhoto.ThumbnailLargeUrl = new Uri(newPhoto.largeThumbnailUrl); // required //localPhoto.ContentUrl = new Uri(newPhoto.fullSizeUrl); // optional photosToSave.Add(localPhoto); // Check if the current photo is the most recent one if (null == mostRecent || (localPhoto.CreationTime > mostRecent.CreationTime)) { mostRecent = localPhoto; } if (photosToSave.Count > 500) { // Save the photos in one bulk transaction, note the transaction can't be larger than 1000, // but we break it into 500 for good measure await manager.SaveMediaItemsAsync(photosToSave); photosToSave.Clear(); } } else { // The photo is still on the server. Keep it. photosToDelete.Remove(newPhoto.id); } } // Most server APIs will provide a distinct cover image // Here we use the most recent photo update the cover image if (null != mostRecent && album.CoverImageUrl != mostRecent.ThumbnailSmallUrl) { await album.SetCoverImageAsync(null); album.CoverImageUrl = mostRecent.ThumbnailSmallUrl; } // Update last modified time album.VersionStamp = newVersionStamp; // Calling SavePictureAlbumAsync will flicker the entire album page. // It can produce a poor user experience if called everytime // we receive a newDownloadAlbumItemsOperation. // For that reason, we only call this when the album has been updated. // So, we always check if the VersionStamp has been updated. await manager.SavePictureAlbumAsync(album); // Save all the photos in one bulk transaction: if (photosToSave.Count > 0) { await manager.SaveMediaItemsAsync(photosToSave); } // Purge old photos if (null != photosToDelete) { foreach (OnlinePicture photo in photosToDelete.Values) { await manager.DeleteMediaItemAsync(photo); } } } } Logger.Log("Agent", "Precessing DownloadAlbumItemsOperation for Id=" + operation.ParentAlbumId); } catch (Exception e) { Helpers.HandleException(e); } finally { operation.SafeNotifyCompletion(); } }
/// <summary> /// Because the app has registered to support "Photos" extension the agent will be invoked /// and requested to download the album items when the user taps on our tile /// in the photos hub. This method handles the operation by synchronizing the local /// store with our web server (Bing Images). /// </summary> /// <param name="operation">The operation that we need to perform</param> private async Task ProcessOperation(DownloadAlbumItemsOperation operation) { try { Logger.Log("Agent", "DownloadAlbumItemsOperation(" + operation.ParentAlbumId + ")"); if (string.IsNullOrEmpty(operation.ParentAlbumId)) { // An empty ParentAlbumId means that we need to populate the root album OnlinePictureAlbum rootAlbum = await manager.GetRootPictureAlbumAsync(); // Let's add the top level albums // Simulate server request to get the top level albums // (note: this code sample builds the list statically) List<BingApi.Album> topLevelAlbums = BingApi.GetAlbums(); foreach (BingApi.Album newAlbum in topLevelAlbums) { OnlinePictureAlbum album = await manager.GetPictureAlbumByRemoteIdAsync(newAlbum.id); if (null == album) { album = manager.CreatePictureAlbum(newAlbum.id, rootAlbum.Id); album.Title = newAlbum.title; // The albums that have the RequiresAuthentication flag set will // trigger a DownloadImageOperation every time the Photos app needs // to display an image that hasn't already been downloaded. album.RequiresAuthentication = newAlbum.authRequired; await manager.SavePictureAlbumAsync(album); } } } else { // ParentAlbumId is the remote id of the album that we need to populate OnlinePictureAlbum album = await manager.GetPictureAlbumByRemoteIdAsync(operation.ParentAlbumId); // Make a network call to get the most recent VersionStamp string newVersionStamp = await BingApi.GetVersionStampAsync(operation.ParentAlbumId); // Is up to the app to use the VersionStamp on the album to best suit its needs. // The OS doesn't use this value. The app can use it to determine if the album is // up to date. Only trigger a full sync if the album is not up to date. if (album.VersionStamp != newVersionStamp) { // Get all the pictures that are currently in the album OnlineMediaItemQueryResult query = album.GetContentsQuery(); IList<IOnlineMediaItem> oldPictures = await query.GetItemsAsync(); // Mark all current pictures for deletion Dictionary<string, OnlinePicture> photosToDelete = new Dictionary<string, OnlinePicture>(); foreach (IOnlineMediaItem item in oldPictures) { OnlinePicture onlinePicture = item as OnlinePicture; if (null != onlinePicture) { photosToDelete.Add(onlinePicture.RemoteId, onlinePicture); } } // Contact server to download the metadata for all the items in the album List<BingApi.Photo> newPhotos = await BingApi.GetAllPhotosMetadataAsync(operation.ParentAlbumId); // Fill with new photos List<OnlinePicture> photosToSave = new List<OnlinePicture>(); // Save a reference to the most recent photo among the new photos to use it as the cover for the album OnlinePicture mostRecent = null; foreach (BingApi.Photo newPhoto in newPhotos) { OnlinePicture onlinePicture = await manager.GetPictureByRemoteIdAsync(newPhoto.id); if (null == onlinePicture) { OnlinePicture localPhoto = manager.CreatePicture(newPhoto.id, album.Id); localPhoto.Title = newPhoto.title; localPhoto.CreationTime = newPhoto.timestamp; localPhoto.ThumbnailSmallUrl = new Uri(newPhoto.smallThumbnailUrl); // required localPhoto.ThumbnailLargeUrl = new Uri(newPhoto.largeThumbnailUrl); // required //localPhoto.ContentUrl = new Uri(newPhoto.fullSizeUrl); // optional photosToSave.Add(localPhoto); // Check if the current photo is the most recent one if (null == mostRecent || (localPhoto.CreationTime > mostRecent.CreationTime)) { mostRecent = localPhoto; } if (photosToSave.Count > 500) { // Save the photos in one bulk transaction, note the transaction can't be larger than 1000, // but we break it into 500 for good measure await manager.SaveMediaItemsAsync(photosToSave); photosToSave.Clear(); } } else { // The photo is still on the server. Keep it. photosToDelete.Remove(newPhoto.id); } } // Most server APIs will provide a distinct cover image // Here we use the most recent photo update the cover image if (null != mostRecent && album.CoverImageUrl != mostRecent.ThumbnailSmallUrl) { await album.SetCoverImageAsync(null); album.CoverImageUrl = mostRecent.ThumbnailSmallUrl; } // Update last modified time album.VersionStamp = newVersionStamp; // Calling SavePictureAlbumAsync will flicker the entire album page. // It can produce a poor user experience if called everytime // we receive a newDownloadAlbumItemsOperation. // For that reason, we only call this when the album has been updated. // So, we always check if the VersionStamp has been updated. await manager.SavePictureAlbumAsync(album); // Save all the photos in one bulk transaction: if (photosToSave.Count > 0) { await manager.SaveMediaItemsAsync(photosToSave); } // Purge old photos if (null != photosToDelete) { foreach (OnlinePicture photo in photosToDelete.Values) { await manager.DeleteMediaItemAsync(photo); } } } } Logger.Log("Agent", "Precessing DownloadAlbumItemsOperation for Id=" + operation.ParentAlbumId); } catch (Exception e) { Helpers.HandleException(e); } finally { operation.SafeNotifyCompletion(); } }