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。
‧Lock screen settings screen:
擷錄MSDN的圖說明在lock screen settings screen:
看出前二張圖片的差別嗎?在「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:
允許應用程式去確認本身是否為lock screen background provider與設定本身為provider。主要方法如下:
屬性/方法 | 說明 |
IsProviderByCurrentApplication | (Read-only) 識別應用程式是否為目前的lock screen background provider。其值為:true/false。 |
RequestAccessAsync | 設定應用程式成為目前的lock screen background provider。 |
由於RequestAccessAsync是非同步機制,可在實作過程裡加上await來協助處理,以利完成任務;
設定/取得目前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";
‧選擇為"Bing"時,則出現目前Bing提供的圖示無法修改,如下圖:
透過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>
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. 執行結果:
[註] 圖片所有權不屬於本文章,因此,只暫用圖示,範例中的使用到的圖示,請大家自行選擇適合的圖示,謝謝。
[補充]
*使用模擬器怎麼做出Lock Screen的功能,請參考下圖:
[範例程式]
[注意]
*如果更新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是被放在一起的,如下圖:
但是到了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
‧NavigationContext.QueryString Property
‧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?