1
votes

I'm trying to implement a lockscreen background application on Windows Phone 8 using C#. The idea is that when a user clicks a button, PhotoChooserTask is initiated. When he picks a photo from his media library, it's copied to isolated storage and then set as a lockscreen background.

The problem is that Windows Phone requires a unique name for each new lockscreen picture, so the solution has to be the following:

  1. The user selects a photo from the library 2.1 If the current lockscreen picture EndsWith("_A.jpg") the chosen photo is copied to the isolated storage as photobackground_B.jpg and is set as lockscreen background 2.2. Otherwise, if the current lockscreen picture doesn't meet the EndsWith("_A.jpg") condition, then the chosen photo is copied to the isolated storage as photobackground_A.jpg and is set as lockscreen background.

Thus, the A/B switching logic is implemented so that each new lockscreen background has a unique name.

However, my code does not work.In particular the following line throws an exception:

Windows.Phone.System.UserProfile.LockScreen.SetImageUri(new Uri("ms-appdata:///Local/photobackground_A.jpg", UriKind.Absolute));

What seems to be the problem?

P.S. I'm completely new to programming, so I would also greately appreciate an explanation and a proper code sample. Thanks!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Tasks;
using Day2Demo.Resources;
using System.Windows.Media;
using System.IO;
using System.IO.IsolatedStorage;
using Microsoft.Xna.Framework.Media;


namespace Day2Demo
{
    public partial class MainPage : PhoneApplicationPage
    {
        PhotoChooserTask photoChooserTask;
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // Sample code to localize the ApplicationBar
            //BuildLocalizedApplicationBar();
        }





        private async void button1_Click(object sender, RoutedEventArgs e)
        {


            //check if current app provided the lock screen image
            if (!Windows.Phone.System.UserProfile.LockScreenManager.IsProvidedByCurrentApplication)
            {
                //current image not set by current app ask permission
                var permission = await Windows.Phone.System.UserProfile.LockScreenManager.RequestAccessAsync();

                if (permission == Windows.Phone.System.UserProfile.LockScreenRequestResult.Denied)
                {
                    //no permission granted so return without setting the lock screen image
                    return;
                }

            }
            photoChooserTask = new PhotoChooserTask();
            photoChooserTask.Completed += new EventHandler<PhotoResult>(photoChooserTask_Completed);
            photoChooserTask.Show();
        }

        void photoChooserTask_Completed(object sender, PhotoResult e)
        {
            if (e.TaskResult == TaskResult.OK)
            {
                var currentImage = Windows.Phone.System.UserProfile.LockScreen.GetImageUri();
                if (currentImage.ToString().EndsWith("_A.jpg"))
                {

                    var contents = new byte[1024];
                    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        using (var local = new IsolatedStorageFileStream("photobackground_B.jpg", FileMode.Create, store))
                        {
                            int bytes;
                            while ((bytes = e.ChosenPhoto.Read(contents, 0, contents.Length)) > 0)
                            {
                                local.Write(contents, 0, bytes);
                            }

                        }
                        Windows.Phone.System.UserProfile.LockScreen.SetImageUri(new Uri("ms-appdata:///Local/photobackground_B.jpg", UriKind.Absolute));
                    }
                }

                else
                {
                    var contents = new byte[1024];
                    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        using (var local = new IsolatedStorageFileStream("photobackground_A.jpg", FileMode.Create, store))
                        {
                            int bytes;
                            while ((bytes = e.ChosenPhoto.Read(contents, 0, contents.Length)) > 0)
                            {
                                local.Write(contents, 0, bytes);
                            }

                        }
                        Windows.Phone.System.UserProfile.LockScreen.SetImageUri(new Uri("ms-appdata:///Local/photobackground_A.jpg", UriKind.Absolute));
                    }
                }


            }
        }
    }
}
2

2 Answers

1
votes

Here are some suggestions for you:

  1. You may be overcomplicating the matter of naming the file. First, I'd say if the app is the current lock screen manager, delete the existing lock screen image, then create a new image name using Guid.NewGuid. Guids are guaranteed to be unique upon generation so you'll never run into a naming collision here.

  2. You're using antiquated storage APIs that may lock your UI and cause it to become non-responsive. There are new async file storage APIs provided in Windows Phone 8 and it might help to familiarize yourself with them in the future. The code sample provided will give you a start.

  3. The URI you're ultimately going to provide is likely most easily generated by giving the OS a system-relative file path (i.e. C:\) and that's easily accessible from the StorageFile.Path Property.

Modify your event handler to something along the lines of the following code and see how you fare. You will need to add a using directive to import the System.IO namespace to use the OpenStreamForWriteAsync Extension:

private async void photoChooserTask_Completed(object sender, PhotoResult e)
{
    if (e.TaskResult == TaskResult.OK)
    {
        // Load the image source into a writeable bitmap
        BitmapImage bi = new BitmapImage();
        bi.SetSource(e.ChosenPhoto);
        WriteableBitmap wb = new WriteableBitmap(bi);

        // Buffer the photo content in memory (90% quality; adjust parameter as needed)
        byte[] buffer = null;

        using (var ms = new System.IO.MemoryStream())
        {
            int quality = 90;
            e.ChosenPhoto.Seek(0, SeekOrigin.Begin);

            // TODO: Crop or rotate here if needed
            // Resize the photo by changing parameters to SaveJpeg() below if desired

            wb.SaveJpeg(ms, wb.PixelWidth, wb.PixelHeight, 0, quality);
            buffer = ms.ToArray();
        }

        // Save the image to isolated storage with new Win 8 APIs
        var isoFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
        var nextImageName = Guid.NewGuid() + ".jpg";
        var newImageFile = await isoFolder.CreateFileAsync(nextImageName, Windows.Storage.CreationCollisionOption.FailIfExists);
        using (var wfs = await newImageFile.OpenStreamForWriteAsync())
        {
            wfs.Write(buffer, 0, buffer.Length);
        }

        // Use the path property of the StorageFile to set the lock screen URI
        Windows.Phone.System.UserProfile.LockScreen.SetImageUri(new Uri(newImageFile.Path, UriKind.Absolute));
    }
}
1
votes

Thanks lthibodeaux for the awesome idea) Everything worked except for the SetImageUri line.

This one seems to do the business: Windows.Phone.System.UserProfile.LockScreen.SetImageUri(new Uri("ms-appdata:///Local/" + nextImageName, UriKind.Absolute))

Thanks again!