Windows Phone 8 - 修改鎖定螢幕的背景

Windows Phone 8 - 修改鎖定螢幕的背景

WP 7.1 SDK時候,如有閱讀過<Windows Phone 7 – Photo Extensibility>與<Windows Phone 7 – Search Extensibility>

這二篇文章的話,接著往下看Lock screen background的作法,將會發現其機制是相同的,因為共通點就是需要

為WMAppManifest.xaml的<Extensions />增加<Extension />標籤,並且定義固定的ExtensionName與CustomerID。

 

在往下詳細說明之前,先來了解一下lock screen background與lock screen background provider為何?

‧Lock screen background

     擷錄MSDN上的圖示,說明lock screen background的圖示範圍如下圖所此出的background area。

     IC619124

 

‧Lock screen settings screen

     擷錄MSDN的圖說明在lock screen settings screen:

112111113

看出前二張圖片的差別嗎?在「Background」的選項不同了,預設是"choose background",其實裡面有二個預設的項目

如圖三,具有photo與Bing二項,選擇二個其中一個將成為lock screen background provider,也代表background area的圖像

將由指定的provider來提供。因此,今天介紹的就是如何實作一個lock screen background provider。

 

 

首先,在WP8裡提供了二個管理Lock screen background的APIs,分別為LockScreenManager與LockScreen,

往下先針對這二個APIs加以說明,有助於了解實作機制上的代碼:

 

Windows.Phone.System.UserProfile

       該namespace下提供允許應用程式與系統的lock screen功能進行整合。包括二種類型:Classes與Enumerations,如下:

(a). Classes

       LockScreenManager

            允許應用程式去確認本身是否為lock screen background provider與設定本身為provider。主要方法如下:

屬性/方法 說明
IsProviderByCurrentApplication (Read-only) 識別應用程式是否為目前的lock screen background provider。其值為:true/false。
RequestAccessAsync 設定應用程式成為目前的lock screen background provider。

            由於RequestAccessAsync是非同步機制,可在實作過程裡加上await來協助處理,以利完成任務;

 

       LockScreen

            設定/取得目前lock screen background的圖示。主要方法如下:

方法名稱 說明
GetImageUri 取得目前lock screen background的Uniform Resource Identifier (URI)。
SetImageUri 設定特定圖片的Uniform Resource Identifier (URI)為lock screen background。

           此處要注意的是使用的均是URI,開發時建議可以使用「ms-appx:///」或「ms-appdata:///Local/」方便組合URI。

 

(b). Enumerations
        LockscreenRequestResult

             需搭配LockScreenManager.RequestAccessAsync()方法一起使用,因為該列舉用於識別應用程式請求成為

             目前lock screen background provider是否成功。其值如下:

成員 說明
Denied 0 應用程式未被設定為lock screen background provider。
Granted 1 應用程式設定為lock screen background provider。

 

 

上述介紹了的APIs後,接著往下說明如何實作一個應用程式成為lock screen background provider,提供用戶可以選擇

修改lock screen background的圖像。

 

主要實作步驟說明:

1. WMAppManifest.xml定義App為lock screen background provider;

2. 實作取得圖片與修改lock screen background的邏輯;

3. 在專案根目錄加入App的DefaultLockScreen.jpg;

4. 在App中增加連結至lock screen settings screen;

 

1. WMAppManifest.xml定義App成為lock screen background provider

      第一步需要宣告自己的App是一個lock screen background provider,可處理系統intent至該App修改背景圖的任務。     

因此,需要在WMAppManifest.xml的<Extension />標籤,宣告要求支援的能力,如下範例:

   1: <Extensions>
   2:     <!--
   3:         //在<Extensions />標籤中新的Extension屬性,
   4:         //ExtensionName與CustomerID是固定的,
   5:         //讓在設定的更換背景時可以呼叫到這個App。
   6:     -->
   7:     <Extension ExtensionName="LockScreen_Background" 
   8:                ConsumerID="{111DFF24-AA15-4A96-8006-2BFF8122084F}" 
   9:                TaskID="_default" />
  10: </Extensions>

其CusmerID是固定的:111DFF24-AA15-4A96-8006-2BFF8122084F;ExtensionName為:LockScreen_Background;

<Extensions />的標籤,記得是加在<Tokens />的下方。

    

 

2. 實作App取得圖像與修改lock screen background的處理邏輯

     此處主要實作識別並取得應用程式為lock screen background provider的能力,最後設定lock screen background。

由於這一些需要使用上述敘述的LockScreenManager與LockScreen來完成,因此,請先了解二個APIs的使用機制。

   1: private async void LockHelper(string filePathOfTheImage, bool isAppResource)
   2: {
   3:     try
   4:     {
   5:         //識別目前是否為lock screen background provider
   6:         var isProvider = Windows.Phone.System.UserProfile.LockScreenManager.IsProvidedByCurrentApplication;
   7:         if (isProvider == false)
   8:         {
   9:             //呼叫RequestAccessAsync()請求設定為lock screen background provider
  10:             //系統會彈出對話框告知用戶是否允許設定。
  11:             var op = await Windows.Phone.System.UserProfile.LockScreenManager.RequestAccessAsync();
  12:  
  13:             // Only do further work if the access was granted.
  14:             //識別只有在成功取得設定後,才可以往下進行。
  15:             if (op == Windows.Phone.System.UserProfile.LockScreenRequestResult.Granted)
  16:                 isProvider = true;
  17:         }
  18:  
  19:         if (isProvider)
  20:         {
  21:             //在這個步驟,App被設定為lock screen background provider。
  22:             //將選擇的圖示由ms-appdata:///或ms-appx///中讀取出來,並且指定給LockScreen。
  23:             // ms-appdata points to the root of the local app data folder.
  24:             // ms-appx points to the Local app install folder, to reference resources bundled in the XAP package.
  25:             //組合特定的URI
  26:             var schema = isAppResource ? "ms-appx:///" : "ms-appdata:///Local/";
  27:             var uri = new Uri(schema + filePathOfTheImage, UriKind.Absolute);
  28:             
  29:             // 設定lock screen background image。
  30:             Windows.Phone.System.UserProfile.LockScreen.SetImageUri(uri);
  31:  
  32:             // 取得lock screen background image的URI。
  33:             var currentImage = Windows.Phone.System.UserProfile.LockScreen.GetImageUri();
  34:             System.Diagnostics.Debug.WriteLine("The new lock screen background image is set to {0}", currentImage.ToString());
  35:         }
  36:         else
  37:         {
  38:             MessageBox.Show("You said no, so I can't update your background.");
  39:         }
  40:     }
  41:     catch (System.Exception ex)
  42:     {
  43:         System.Diagnostics.Debug.WriteLine(ex.ToString());
  44:     }
  45: }

上述程式主要為識別並取得lock screen background provider的能力,接著透過參數的檔案名稱,重新組合實際的

URI,接著透過LockScreen指定新的Image路徑。

 

[注意]

*如果應用程本身非目前的lock screen background provider需要向使用者提示是否設定為provider

*在Background Agent下,不允許使用LockScreenManager.RequestAccessAsync()的方法

 

 

3. 設定App支援成為為一個預設的Lock screen background image

     由於WP8系統允許讓用戶在「設定」畫面中,指定特定的App成為預設的lock screen background provider,為了這個原因,

建議在專案的根目錄(或XAP的根目錄)裡增加一個「DefaultLockScreen.jpg」的檔案,讓該App可在「設定」畫面中得以識別。

 

 

4. 處理來自lock screen settings screen的參數

     如果App在電話的lock screen settings screen中被設定為預設的lock screen background provider,在該畫面中會出現一個

tap button」的按鈕。當User點擊該按鈕時,系統會自動啟動App,並且帶入固定的QueryString。因此,在App裡需要

處理該QueryString帶來的參數,例如:在App裡客製一個lock screen settings screen或是顯示個訊息通知Image已被更新。

如果您仔細操作過WP8模擬器,您會發現[tap button]隨著選擇background的不同而有所變化,如下:

‧選擇background為"photo"時會出現"change photo"

     114

‧選擇為"Bing"時,則出現目前Bing提供的圖示無法修改,如下圖

    111

 

透過Override OnNavigateTo的方法來承接到指定的QueryString時,進行lock screen background的設定。如下:

   1: protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
   2: {
   3:     base.OnNavigatedTo(e);
   4:     //固定的Query string key
   5:     string lockscreenKey = "WallpaperSettings";
   6:     string lockscreenValue = "0";
   7:     //取得值
   8:     bool lockscreenValueExists = NavigationContext.QueryString.TryGetValue(lockscreenKey, out lockscreenValue);
   9:  
  10:     if (lockscreenValueExists)
  11:     {
  12:         //識別是由lock screen settings screen進來的,接著進行要處理的邏輯。
  13:     }
  14: }

 

[注意]

*如果是來自lock screen settings screen的QueryString,其中有一組key為:WallpaperSettings,可用於識別。

 

 

5. 在App中增加直接連結至lock screen settings screen

     WP8也提供在App裡增加直接連結至lock screen settings screen的功能,為什麼會需要這樣的功能呢?主要是因為

雖然用戶可以設定App為lock screen background provider,但無法在該App透過程式化取消該App為Provider的設定

因此,用戶如要調整就必需前往電話中的settings screen裡手動調整,此時如果在App增加連結的功能將會非常方便。

如下程式碼:

   1: #region 前往Lock Screen Settings Screen
   2: private async void GoToLockSettings_Click(object sender, RoutedEventArgs e)
   3: {
   4:     //在程式裡指定特定的URI,進入lock screen settings screen.
   5:     var op = await Windows.System.Launcher.LaunchUriAsync(
   6:                    new Uri("ms-settings-lock:"));
   7: }
   8: #endregion

====

以上為說明如何實作一個可成為lock screen background provider的應用程式,裡面包括如何請求取得成為provider的能力、

重新調整background area的範圍、承接由lock screen settings screen進入應用程式的處理與呼叫進入lock screen settings screen。

 

接下來透過範例來加以說明:

1. 延用<Windows Phone 7 – 用手勢(Flick)做一個簡單的水平ListBox>的範例列出可被設定為lock screen background的圖示

    請至該文章取得範例程式,接著往下補上對應的程式碼;並且調整畫面為如下的XAML;

   1: <!--TitlePanel contains the name of the application and page title-->
   2: <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,0">
   3:     <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
   4:     <!--<TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> -->
   5:     <Button x:Name="btnSetting" Content="Setting" Margin="9,-7,0,0" Click="btnSetting_Click"/>
   6: </StackPanel>
   7:  
   8: <!--ContentPanel - place additional content here-->
   9: <Grid x:Name="ContentPanel" Grid.Row="1" Margin="0,0,0,0">
  10:     <Grid.RowDefinitions>
  11:         <RowDefinition Height="5*" />
  12:         <RowDefinition Height="95*" />
  13:     </Grid.RowDefinitions>
  14:     <!-- 定義五個圈 -->
  15:     <StackPanel x:Name="splEllipses"
  16:         Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center">
  17:         <Ellipse x:Name="elpA" Fill="#FFF4F4F5"
  18:                  Stroke="Black" Width="23" Height="23" Margin="0,0,5,0" />
  19:         <Ellipse x:Name="elpB" Fill="#FFF4F4F5"
  20:                  Stroke="Black" Width="23" Height="23" Margin="0,0,5,0"/>
  21:         <Ellipse x:Name="elpC" Fill="#FFF4F4F5"
  22:                  Stroke="Black" Width="23" Height="23" Margin="0,0,5,0"/>
  23:         <Ellipse x:Name="elpD" Fill="#FFF4F4F5"
  24:                  Stroke="Black" Width="23" Height="23" Margin="0,0,5,0"/>
  25:         <Ellipse x:Name="elpE" Fill="#FFF4F4F5"
  26:                  Stroke="Black" Width="23" Height="23" Margin="0,0,5,0"/>
  27:     </StackPanel>
  28:     <!-- 定義要用到的Image物件與GestureListener -->
  29:     <StackPanel Grid.Row="1">
  30:         <Canvas>
  31:             <Image x:Name="imgSource" Width="480" Height="603"
  32:                    Source="/Assets/Images/a.jpg" Stretch="Fill">
  33:                 <wp7toolkit:GestureService.GestureListener>
  34:                     <wp7toolkit:GestureListener
  35:                     Flick="GestureListener_Flick"
  36:                     DoubleTap="GestureListener_DoubleTap"
  37:                     DragDelta="GestureListener_DragDelta"
  38:                     DragStarted="GestureListener_DragStarted"
  39:                     DragCompleted="GestureListener_DragCompleted">
  40:                     </wp7toolkit:GestureListener>
  41:                 </wp7toolkit:GestureService.GestureListener>
  42:                 <Image.RenderTransform>
  43:                     <TranslateTransform x:Name="translation" />
  44:                 </Image.RenderTransform>
  45:             </Image>
  46:         </Canvas>
  47:     </StackPanel>
  48: </Grid>

       如右圖:115

 

2. 至WMAppManifest.xml加上宣告支援LockScreen_Background的定義

   1: <Extensions>
   2:   <Extension ExtensionName="LockScreen_Background"
   3:              ConsumerID="{111DFF24-AA15-4A96-8006-2BFF8122084F}"
   4:              TaskID="_default" />
   5: </Extensions>

 

3. 加入取得lock screen background provider權利與設定lock screen background的功能

   1: private async void LockHelper(string filePathOfTheImage, bool isAppResource)
   2: {
   3:     try
   4:     {
   5:         //識別目前是否為lock screen background provider
   6:         var isProvider = Windows.Phone.System.UserProfile.LockScreenManager.IsProvidedByCurrentApplication;
   7:         if (isProvider == false)
   8:         {
   9:             //呼叫RequestAccessAsync()請求設定為lock screen background provider
  10:             //系統會彈出對話框告知用戶是否允許設定。
  11:             var op = await Windows.Phone.System.UserProfile.LockScreenManager.RequestAccessAsync();
  12:  
  13:             // Only do further work if the access was granted.
  14:             //識別只有在成功取得設定後,才可以往下進行。
  15:             if (op == Windows.Phone.System.UserProfile.LockScreenRequestResult.Granted)
  16:                 isProvider = true;
  17:         }
  18:  
  19:         if (isProvider)
  20:         {
  21:             //在這個步驟,App被設定為lock screen background provider。
  22:             //將選擇的圖示由ms-appdata:///或ms-appx///中讀取出來,並且指定給LockScreen。
  23:             // ms-appdata points to the root of the local app data folder.
  24:             // ms-appx points to the Local app install folder, to reference resources bundled in the XAP package.
  25:             //組合特定的URI
  26:             //var schema = isAppResource ? "ms-appx:///" : "ms-appdata:///Local/";
  27:             //var uri = new Uri(schema + filePathOfTheImage, UriKind.Absolute);
  28:             var uri = new Uri(filePathOfTheImage, UriKind.Absolute);
  29:  
  30:             // Set the lock screen background image.
  31:             Windows.Phone.System.UserProfile.LockScreen.SetImageUri(uri);
  32:  
  33:             // Get the URI of the lock screen background image.
  34:             var currentImage = Windows.Phone.System.UserProfile.LockScreen.GetImageUri();
  35:             System.Diagnostics.Debug.WriteLine("The new lock screen background image is set to {0}", currentImage.ToString());
  36:         }
  37:         else
  38:         {
  39:             MessageBox.Show("You said no, so I can't update your background.");
  40:         }
  41:     }
  42:     catch (System.Exception ex)
  43:     {
  44:         System.Diagnostics.Debug.WriteLine(ex.ToString());
  45:     }
  46: }

     此處只有取消URI組合的功能,改由第4步的URL組合為基準;要注意,如果是使用ms-appx:////或ms-appdata:///在設

     定時要使用"UriKind.Absolute";

 

4. 增加Setting的事件與儲存指定圖檔至Isolated Storage中的方法

     (4-1). Settings的事件

   1: private void btnSetting_Click(object sender, RoutedEventArgs e)
   2: {
   3:     //取得目前顯示畫面的圖示;
   4:     BitmapImage tBitmap = imgSource.Source as BitmapImage;
   5:  
   6:     //將檔案寫入Isolated Storage,並取得實際的path;
   7:     string tUri = WriteImageToFile(tBitmap, gImageList[gCurrentIdx]);
   8:  
   9:     //增加標記,讓onnavigatedto()回來時可以使用;
  10:     if (IsolatedStorageSettings.ApplicationSettings.Contains("LockScreenImage") == false)
  11:         IsolatedStorageSettings.ApplicationSettings.Add("LockScreenImage", gImageList[gCurrentIdx]);
  12:     else
  13:         IsolatedStorageSettings.ApplicationSettings["LockScreenImage"] = gImageList[gCurrentIdx];
  14:  
  15:     //呼叫lock screen background provider的api進行background的更新
  16:     LockHelper(tUri, false);
  17: }

     (4-2). 將指定的圖檔寫入Isolated Storage的方法,並增加標誌提供OnNavigatedTo的使用

   1: private string WriteImageToFile(BitmapImage pBitmap, string pName)
   2: {
   3:     try
   4:     {
   5:         WriteableBitmap tWBitmap = new WriteableBitmap(pBitmap);
   6:         using (IsolatedStorageFile tStorage = IsolatedStorageFile.GetUserStoreForApplication())
   7:         {
   8:             using (IsolatedStorageFileStream tStream = tStorage.CreateFile(pName))
   9:             {
  10:                 tWBitmap.SaveJpeg(tStream, 306, 375, 0, 96);
  11:                 tStream.Close();
  12:             }
  13:         }
  14:         //重組新的URI
  15:         return string.Format("ms-appdata:///local/{0}", pName);
  16:     }
  17:     catch (Exception ex)
  18:     {
  19:         string tMsg = ex.Message;
  20:         return string.Empty;
  21:     }
  22: }

 

5. 增加由lock screen settings screen啟動應用程式的處理

   1: protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
   2: {
   3:     base.OnNavigatedTo(e);
   4:     //固定的Query string key
   5:     string lockscreenKey = "WallpaperSettings";
   6:     string lockscreenValue = "0";
   7:     //取得值
   8:     bool lockscreenValueExists = NavigationContext.QueryString.TryGetValue(lockscreenKey, out lockscreenValue);
   9:  
  10:     if (lockscreenValueExists)
  11:     {
  12:         //識別是由lock screen settings screen進來的,接著進行要處理的邏輯。
  13:         //此處範例為直接顯示設定為lock screen background的圖示,而非預設的第一張。
  14:         if (IsolatedStorageSettings.ApplicationSettings.Contains("LockScreenImage") == true)
  15:         {
  16:             string tImage = IsolatedStorageSettings.ApplicationSettings["LockScreenImage"].ToString();
  17:             int tIdx = gImageList.IndexOf(tImage);
  18:             gCurrentIdx = tIdx;
  19:             UpdateImage();
  20:         }
  21:     }
  22: }

 

6. 執行結果

     116117118

     119120

[註] 圖片所有權不屬於本文章,因此,只暫用圖示,範例中的使用到的圖示,請大家自行選擇適合的圖示,謝謝

 

[補充]

*使用模擬器怎麼做出Lock Screen的功能,請參考下圖:

   121image

 

[範例程式]

 

[注意]

*如果更新Lock Screen background使用的Image來自Isolated Storage,必須提供一個唯一的名字(unique file name)加以識別;

  在<Lock screen background for Windows Phone 8>裡有介紹一個簡單的方法,幫忙把指定的Image重新換一個名字,

  寫到Isolated Storage中。如下:

   1: string fileName;
   2: var currentImage = LockScreen.GetImageUri();
   3:  
   4: if (currentImage.ToString().EndsWith("_A.jpg"))
   5: {
   6:     fileName = "LiveLockBackground_B.jpg";
   7: }
   8: else
   9: {
  10:     fileName = "LiveLockBackground_A.jpg";
  11: }
  12:  
  13: var lockImage = string.Format("{0}", fileName);
  14:  
  15: // 增加寫入Isolated Storage的程式段;

 

======

過去在WP 7.1 SDK時候,Lock與Wallpaper是被放在一起的,如下圖:

Screen Capture (2)

但是到了WP8開始,lock screen被獨立出來,Wallpaper不見了,改變的是讓lock screen指定的background area,

可以有動態呈現圖像,其來源包括:Photo hub、Bing、第三方App(也包括自己開發的App),這樣動態的呈現,

讓過去只能選擇Wallpaper的功能變成更加豐富圖像的呈現,我覺得是WP8裡蠻特別的一塊。

希望上述文章說明有助於大家實作自己的lock screen background provider。

 

References:

Lock screen background for Windows Phone 8

Data for Windows Phone

NavigationContext.QueryString Property

Tiles for Windows Phone

Windows Phone 8 更换锁屏界面图片

Windows Phone 支持锁屏的应用

8 days of Windows Phone 8 | Day 2: Live tiles & Lock screen

[WP8] Programmatically change the lock screen picture

How do I take a bitmap image and save as a JPEG image file on a Windows Phone 7 device?

 

Dotblogs Tags: