updated fast resume code for app

This commit is contained in:
Dale Stammen 2014-06-12 16:36:53 -07:00
parent 29b9da34ea
commit 2d913470a0
8 changed files with 499 additions and 223 deletions

View File

@ -1,17 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Diagnostics;
using System.Resources;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Markup;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.IO.IsolatedStorage;
using PhoneDirect3DXamlAppInterop.Resources;
namespace PhoneDirect3DXamlAppInterop
{
@ -21,7 +17,28 @@ namespace PhoneDirect3DXamlAppInterop
/// Provides easy access to the root frame of the Phone Application.
/// </summary>
/// <returns>The root frame of the Phone Application.</returns>
public PhoneApplicationFrame RootFrame { get; private set; }
public static PhoneApplicationFrame RootFrame { get; private set; }
enum SessionType
{
None,
Home,
DeepLink
}
// Set to Home when the app is launched from Primary tile.
// Set to DeepLink when the app is launched from Deep Link.
private SessionType sessionType = SessionType.None;
// Set to true when the page navigation is being reset
bool wasRelaunched = false;
// set to true when 5 min passed since the app was relaunched
bool mustClearPagestack = false;
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
/// <summary>
/// Constructor for the Application object.
@ -31,17 +48,20 @@ namespace PhoneDirect3DXamlAppInterop
// Global handler for uncaught exceptions.
UnhandledException += Application_UnhandledException;
// Standard Silverlight initialization
// Standard XAML initialization
InitializeComponent();
// Phone-specific initialization
InitializePhoneApplication();
// Language display initialization
InitializeLanguage();
// Show graphics profiling information while debugging.
if (System.Diagnostics.Debugger.IsAttached)
if (Debugger.IsAttached)
{
// Display the current frame rate counters.
Application.Current.Host.Settings.EnableFrameRateCounter = false;
Application.Current.Host.Settings.EnableFrameRateCounter = true;
// Show the areas of the app that are being redrawn in each frame.
//Application.Current.Host.Settings.EnableRedrawRegions = true;
@ -50,8 +70,8 @@ namespace PhoneDirect3DXamlAppInterop
// which shows areas of a page that are handed off to GPU with a colored overlay.
//Application.Current.Host.Settings.EnableCacheVisualization = true;
// Disable the application idle detection by setting the UserIdleDetectionMode property of the
// application's PhoneApplicationService object to Disabled.
// Prevent the screen from turning off while under the debugger by disabling
// the application's idle detection.
// Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
// and consume battery power when the user is not using the phone.
PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
@ -63,43 +83,63 @@ namespace PhoneDirect3DXamlAppInterop
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
// When a new instance of the app is launched, clear all deactivation settings
RemoveCurrentDeactivationSettings();
}
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
// If some interval has passed since the app was deactivated (30 seconds in this example),
// then remember to clear the back stack of pages
mustClearPagestack = CheckDeactivationTimeStamp();
// If IsApplicationInstancePreserved is not true, then set the session type to the value
// saved in isolated storage. This will make sure the session type is correct for an
// app that is being resumed after being tombstoned.
if (!e.IsApplicationInstancePreserved)
{
RestoreSessionType();
}
}
// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
// When the applicaiton is deactivated, save the current deactivation settings to isolated storage
SaveCurrentDeactivationSettings();
}
// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
// When the application closes, delete any deactivation settings from isolated storage
RemoveCurrentDeactivationSettings();
}
// Code to execute if a navigation fails
private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
if (Debugger.IsAttached)
{
// A navigation has failed; break into the debugger
System.Diagnostics.Debugger.Break();
Debugger.Break();
}
}
// Code to execute on Unhandled Exceptions
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
if (Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
Debugger.Break();
}
}
@ -125,10 +165,80 @@ namespace PhoneDirect3DXamlAppInterop
// Handle reset requests for clearing the backstack
RootFrame.Navigated += CheckForResetNavigation;
// Monitor deep link launching
RootFrame.Navigating += RootFrame_Navigating;
// Ensure we don't initialize again
phoneApplicationInitialized = true;
}
// Event handler for the Navigating event of the root frame. Use this handler to modify
// the default navigation behavior.
void RootFrame_Navigating(object sender, NavigatingCancelEventArgs e)
{
// If the session type is None or New, check the navigation Uri to determine if the
// navigation is a deep link or if it points to the app's main page.
if (sessionType == SessionType.None && e.NavigationMode == NavigationMode.New)
{
// This block will run if the current navigation is part of the app's intial launch
// Keep track of Session Type
if (e.Uri.ToString().Contains("DeepLink=true"))
{
sessionType = SessionType.DeepLink;
}
else if (e.Uri.ToString().Contains("/MainPage.xaml"))
{
sessionType = SessionType.Home;
}
}
if (e.NavigationMode == NavigationMode.Reset)
{
// This block will execute if the current navigation is a relaunch.
// If so, another navigation will be coming, so this records that a relaunch just happened
// so that the next navigation can use this info.
wasRelaunched = true;
}
else if (e.NavigationMode == NavigationMode.New && wasRelaunched)
{
// This block will run if the previous navigation was a relaunch
wasRelaunched = false;
if (e.Uri.ToString().Contains("DeepLink=true"))
{
// This block will run if the launch Uri contains "DeepLink=true" which
// was specified when the secondary tile was created in MainPage.xaml.cs
sessionType = SessionType.DeepLink;
// The app was relaunched via a Deep Link.
// The page stack will be cleared.
}
else if (e.Uri.ToString().Contains("/MainPage.xaml"))
{
// This block will run if the navigation Uri is the main page
if (sessionType == SessionType.DeepLink)
{
// When the app was previously launched via Deep Link and relaunched via Main Tile, we need to clear the page stack.
sessionType = SessionType.Home;
}
else
{
if (!mustClearPagestack)
{
//The app was previously launched via Main Tile and relaunched via Main Tile. Cancel the navigation to resume.
e.Cancel = true;
RootFrame.Navigated -= ClearBackStackAfterReset;
}
}
}
mustClearPagestack = false;
}
}
// Do not add any additional code to this method
private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
{
@ -153,7 +263,7 @@ namespace PhoneDirect3DXamlAppInterop
// Unregister the event so it doesn't get called again
RootFrame.Navigated -= ClearBackStackAfterReset;
// Only clear the stack for 'new' (forward) navigations
// Only clear the stack for 'new' (forward) and 'refresh' navigations
if (e.NavigationMode != NavigationMode.New)
return;
@ -165,5 +275,149 @@ namespace PhoneDirect3DXamlAppInterop
}
#endregion
// Initialize the app's font and flow direction as defined in its localized resource strings.
//
// To ensure that the font of your application is aligned with its supported languages and that the
// FlowDirection for each of those languages follows its traditional direction, ResourceLanguage
// and ResourceFlowDirection should be initialized in each resx file to match these values with that
// file's culture. For example:
//
// AppResources.es-ES.resx
// ResourceLanguage's value should be "es-ES"
// ResourceFlowDirection's value should be "LeftToRight"
//
// AppResources.ar-SA.resx
// ResourceLanguage's value should be "ar-SA"
// ResourceFlowDirection's value should be "RightToLeft"
//
// For more info on localizing Windows Phone apps see http://go.microsoft.com/fwlink/?LinkId=262072.
//
private void InitializeLanguage()
{
try
{
// Set the font to match the display language defined by the
// ResourceLanguage resource string for each supported language.
//
// Fall back to the font of the neutral language if the Display
// language of the phone is not supported.
//
// If a compiler error is hit then ResourceLanguage is missing from
// the resource file.
RootFrame.Language = XmlLanguage.GetLanguage(AppResources.ResourceLanguage);
// Set the FlowDirection of all elements under the root frame based
// on the ResourceFlowDirection resource string for each
// supported language.
//
// If a compiler error is hit then ResourceFlowDirection is missing from
// the resource file.
FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection);
RootFrame.FlowDirection = flow;
}
catch
{
// If an exception is caught here it is most likely due to either
// ResourceLangauge not being correctly set to a supported language
// code or ResourceFlowDirection is set to a value other than LeftToRight
// or RightToLeft.
if (Debugger.IsAttached)
{
Debugger.Break();
}
throw;
}
}
// Helper method for adding or updating a key/value pair in isolated storage
public bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
// If the key exists
if (settings.Contains(Key))
{
// If the value has changed
if (settings[Key] != value)
{
// Store the new value
settings[Key] = value;
valueChanged = true;
}
}
// Otherwise create the key.
else
{
settings.Add(Key, value);
valueChanged = true;
}
return valueChanged;
}
// Helper method for removing a key/value pair from isolated storage
public void RemoveValue(string Key)
{
// If the key exists
if (settings.Contains(Key))
{
settings.Remove(Key);
}
}
// Called when the app is deactivating. Saves the time of the deactivation and the
// session type of the app instance to isolated storage.
public void SaveCurrentDeactivationSettings()
{
if (AddOrUpdateValue("DeactivateTime", DateTimeOffset.Now))
{
settings.Save();
}
if (AddOrUpdateValue("SessionType", sessionType))
{
settings.Save();
}
}
// Called when the app is launched or closed. Removes all deactivation settings from
// isolated storage
public void RemoveCurrentDeactivationSettings()
{
RemoveValue("DeactivateTime");
RemoveValue("SessionType");
settings.Save();
}
// Helper method to determine if the interval since the app was deactivated is
// greater than 30 seconds
bool CheckDeactivationTimeStamp()
{
DateTimeOffset lastDeactivated;
if (settings.Contains("DeactivateTime"))
{
lastDeactivated = (DateTimeOffset)settings["DeactivateTime"];
}
var currentDuration = DateTimeOffset.Now.Subtract(lastDeactivated);
return TimeSpan.FromSeconds(currentDuration.TotalSeconds) > TimeSpan.FromSeconds(30);
}
// Helper method to restore the session type from isolated storage.
void RestoreSessionType()
{
if (settings.Contains("SessionType"))
{
sessionType = (SessionType)settings["SessionType"];
}
}
}
}

View File

@ -140,45 +140,22 @@ namespace PhoneDirect3DXamlAppInterop
RootFrame.Navigated -= CompleteInitializePhoneApplication;
}
private bool _isResume = false;
private void CheckForResetNavigation(object sender, NavigationEventArgs e)
{
// If the app has received a 'reset' navigation, then we need to check
// on the next navigation to see if the page stack should be reset
if (e.NavigationMode == NavigationMode.Reset)
{
RootFrame.Navigating += HandlerFotResetNavigating;
_isResume = true;
}
else
{
if (_isResume && e.NavigationMode == NavigationMode.Refresh)
{
RootFrame.Navigating -= HandlerFotResetNavigating;
_isResume = false;
}
}
}
private void HandlerFotResetNavigating(object sender, NavigatingCancelEventArgs e)
{
RootFrame.Navigating -= HandlerFotResetNavigating;
if (e.Uri.OriginalString.Contains("MainPage.xaml"))
{
e.Cancel = true;
}
else
{
RootFrame.Navigated += ClearBackStackAfterReset;
}
_isResume = false;
}
private void ClearBackStackAfterReset(object sender, NavigationEventArgs e)
{
// Unregister the event so it doesn't get called again
RootFrame.Navigated -= ClearBackStackAfterReset;
// Only clear the stack for 'new' (forward) navigations
if (e.NavigationMode != NavigationMode.New)
// Only clear the stack for 'new' (forward) and 'refresh' navigations
if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh)
return;
// For UI consistency, clear the entire page stack

View File

@ -1,15 +1,14 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17626
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace PhoneDirect3DXamlAppInterop.Resources
{
namespace PhoneDirect3DXamlAppInterop.Resources {
using System;
@ -23,28 +22,23 @@ namespace PhoneDirect3DXamlAppInterop.Resources
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AppResources
{
public class AppResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AppResources()
{
internal AppResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager
{
get
{
if (object.ReferenceEquals(resourceMan, null))
{
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PhoneDirect3DXamlAppInterop.Resources.AppResources", typeof(AppResources).Assembly);
resourceMan = temp;
}
@ -57,14 +51,11 @@ namespace PhoneDirect3DXamlAppInterop.Resources
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture
{
get
{
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set
{
set {
resourceCulture = value;
}
}
@ -72,12 +63,28 @@ namespace PhoneDirect3DXamlAppInterop.Resources
/// <summary>
/// Looks up a localized string similar to MY APPLICATION.
/// </summary>
public static string ApplicationTitle
{
get
{
public static string ApplicationTitle {
get {
return ResourceManager.GetString("ApplicationTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to LeftToRight.
/// </summary>
public static string ResourceFlowDirection {
get {
return ResourceManager.GetString("ResourceFlowDirection", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to en-US.
/// </summary>
public static string ResourceLanguage {
get {
return ResourceManager.GetString("ResourceLanguage", resourceCulture);
}
}
}
}

View File

@ -120,4 +120,12 @@
<data name="ApplicationTitle" xml:space="preserve">
<value>MY APPLICATION</value>
</data>
<data name="ResourceFlowDirection" xml:space="preserve">
<value>LeftToRight</value>
<comment>Controls the FlowDirection for all elements in the RootFrame. Set to the traditional direction of this resource file's language</comment>
</data>
<data name="ResourceLanguage" xml:space="preserve">
<value>en-US</value>
<comment>Controls the Language and ensures that the font for all elements in the RootFrame aligns with the app's language. Set to the language code of this resource file's language.</comment>
</data>
</root>

View File

@ -1,15 +1,14 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17626
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace PhoneDirect3DXamlAppInterop.Resources
{
namespace PhoneDirect3DXamlAppInterop.Resources {
using System;
@ -23,28 +22,23 @@ namespace PhoneDirect3DXamlAppInterop.Resources
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AppResources
{
public class AppResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AppResources()
{
internal AppResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager
{
get
{
if (object.ReferenceEquals(resourceMan, null))
{
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PhoneDirect3DXamlAppInterop.Resources.AppResources", typeof(AppResources).Assembly);
resourceMan = temp;
}
@ -57,14 +51,11 @@ namespace PhoneDirect3DXamlAppInterop.Resources
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture
{
get
{
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set
{
set {
resourceCulture = value;
}
}
@ -72,12 +63,28 @@ namespace PhoneDirect3DXamlAppInterop.Resources
/// <summary>
/// Looks up a localized string similar to MY APPLICATION.
/// </summary>
public static string ApplicationTitle
{
get
{
public static string ApplicationTitle {
get {
return ResourceManager.GetString("ApplicationTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to LeftToRight.
/// </summary>
public static string ResourceFlowDirection {
get {
return ResourceManager.GetString("ResourceFlowDirection", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to en-US.
/// </summary>
public static string ResourceLanguage {
get {
return ResourceManager.GetString("ResourceLanguage", resourceCulture);
}
}
}
}

View File

@ -120,4 +120,12 @@
<data name="ApplicationTitle" xml:space="preserve">
<value>MY APPLICATION</value>
</data>
<data name="ResourceFlowDirection" xml:space="preserve">
<value>LeftToRight</value>
<comment>Controls the FlowDirection for all elements in the RootFrame. Set to the traditional direction of this resource file's language</comment>
</data>
<data name="ResourceLanguage" xml:space="preserve">
<value>en-US</value>
<comment>Controls the Language and ensures that the font for all elements in the RootFrame aligns with the app's language. Set to the language code of this resource file's language.</comment>
</data>
</root>

View File

@ -1,15 +1,14 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17626
// Runtime Version:4.0.30319.34014
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace PhoneDirect3DXamlAppInterop.Resources
{
namespace PhoneDirect3DXamlAppInterop.Resources {
using System;
@ -23,28 +22,23 @@ namespace PhoneDirect3DXamlAppInterop.Resources
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AppResources
{
public class AppResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal AppResources()
{
internal AppResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager
{
get
{
if (object.ReferenceEquals(resourceMan, null))
{
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PhoneDirect3DXamlAppInterop.Resources.AppResources", typeof(AppResources).Assembly);
resourceMan = temp;
}
@ -57,14 +51,11 @@ namespace PhoneDirect3DXamlAppInterop.Resources
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture
{
get
{
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set
{
set {
resourceCulture = value;
}
}
@ -72,12 +63,28 @@ namespace PhoneDirect3DXamlAppInterop.Resources
/// <summary>
/// Looks up a localized string similar to MY APPLICATION.
/// </summary>
public static string ApplicationTitle
{
get
{
public static string ApplicationTitle {
get {
return ResourceManager.GetString("ApplicationTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to LeftToRight.
/// </summary>
public static string ResourceFlowDirection {
get {
return ResourceManager.GetString("ResourceFlowDirection", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to en-US.
/// </summary>
public static string ResourceLanguage {
get {
return ResourceManager.GetString("ResourceLanguage", resourceCulture);
}
}
}
}

View File

@ -120,4 +120,12 @@
<data name="ApplicationTitle" xml:space="preserve">
<value>MY APPLICATION</value>
</data>
<data name="ResourceFlowDirection" xml:space="preserve">
<value>LeftToRight</value>
<comment>Controls the FlowDirection for all elements in the RootFrame. Set to the traditional direction of this resource file's language</comment>
</data>
<data name="ResourceLanguage" xml:space="preserve">
<value>en-US</value>
<comment>Controls the Language and ensures that the font for all elements in the RootFrame aligns with the app's language. Set to the language code of this resource file's language.</comment>
</data>
</root>