[ 
https://issues.apache.org/jira/browse/CB-520?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13256926#comment-13256926
 ] 

Alan Neveu edited comment on CB-520 at 4/23/12 7:58 PM:
--------------------------------------------------------

I wound up modifying CordovaView.xaml.cs in WP7CordovaClassLib.  It turns out 
WP7 apps really need to be able to have more control over the history stack in 
order to comply with Marketplace tech cert requirements.  Here is the source I 
wound up settling on for CordovaView.xaml.cs...  Note the enhancements to void 
GapBrowser_ScriptNotify, and also to void page_BackKeyPress.

/*  
        Licensed under the Apache License, Version 2.0 (the "License");
        you may not use this file except in compliance with the License.
        You may obtain a copy of the License at
        
        http://www.apache.org/licenses/LICENSE-2.0
        
        Unless required by applicable law or agreed to in writing, software
        distributed under the License is distributed on an "AS IS" BASIS,
        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        See the License for the specific language governing permissions and
        limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
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.Shapes;
using Microsoft.Phone.Controls;
using System.IO.IsolatedStorage;
using System.Windows.Resources;
using System.Windows.Interop;
using System.Runtime.Serialization.Json;
using System.IO;
using System.ComponentModel;
using System.Xml.Linq;
using WP7CordovaClassLib.Cordova.Commands;
using System.Diagnostics;
using System.Text;
using WP7CordovaClassLib.Cordova;
using System.Threading;
using Microsoft.Phone.Shell;



namespace WP7CordovaClassLib
{
    public partial class CordovaView : UserControl
    {
       
        /// <summary>
        /// Indicates whether web control has been loaded and no additional 
initialization is needed.
        /// Prevents data clearing during page transitions.
        /// </summary>
        private bool IsBrowserInitialized = false;
        
        /// <summary>
        /// Set when the user attaches a back button handler inside the 
WebBrowser
        /// </summary>
        private bool OverrideBackButton = false;

        /// <summary>
        /// Used for keeping track of our history
        /// </summary>
        private Stack<Uri> history = new Stack<Uri>();
        private bool IsBackButtonPressed = false;


        private static string AppRoot = "/app/";


        /// <summary>
        /// Handles native api calls
        /// </summary>
        private NativeExecution nativeExecution;

        protected DOMStorageHelper domStorageHelper;
        protected OrientationHelper orientationHelper;

        public System.Windows.Controls.Grid _LayoutRoot
        {
            get
            {
                return 
((System.Windows.Controls.Grid)(this.FindName("LayoutRoot")));
            }
        }

        public WebBrowser Browser
        {
            get
            {
                return CordovaBrowser;
            }
        }

        /*
         * Setting StartPageUri only has an effect if called before the view is 
loaded.
         **/
        protected Uri _startPageUri = null;
        public Uri StartPageUri
        {
            get
            {
                if (_startPageUri == null)
                {
                    // default
                    return new Uri( AppRoot + "www/index.html", 
UriKind.Relative);                    
                }
                else
                {
                    return _startPageUri;
                }
            }
            set
            {
                if (!this.IsBrowserInitialized)
                {
                    _startPageUri = value;
                }
            }
        }

        public CordovaView()
        {
            
            InitializeComponent();

            if (DesignerProperties.IsInDesignTool)
            {
                return;
            }


            StartupMode mode = PhoneApplicationService.Current.StartupMode;

            if (mode == StartupMode.Launch)
            {
                PhoneApplicationService service = 
PhoneApplicationService.Current;
                service.Activated += new 
EventHandler<Microsoft.Phone.Shell.ActivatedEventArgs>(AppActivated);
                service.Launching += new 
EventHandler<LaunchingEventArgs>(AppLaunching);
                service.Deactivated += new 
EventHandler<DeactivatedEventArgs>(AppDeactivated);
                service.Closing += new 
EventHandler<ClosingEventArgs>(AppClosing);
            }
            else
            {

            }

            // initializes native execution logic
            this.nativeExecution = new NativeExecution(ref this.CordovaBrowser);
        }

        

        void AppClosing(object sender, ClosingEventArgs e)
        {
            Debug.WriteLine("AppClosing");
        }

        void AppDeactivated(object sender, DeactivatedEventArgs e)
        {
            Debug.WriteLine("AppDeactivated");

            try
            {
                CordovaBrowser.InvokeScript("CordovaCommandResult", new 
string[] { "pause" });
            }
            catch (Exception)
            {
                Debug.WriteLine("Pause event error");
            } 
        }

        void AppLaunching(object sender, LaunchingEventArgs e)
        {
            Debug.WriteLine("AppLaunching");
        }

        void AppActivated(object sender, 
Microsoft.Phone.Shell.ActivatedEventArgs e)
        {
            Debug.WriteLine("AppActivated");
            try
            {
                CordovaBrowser.InvokeScript("CordovaCommandResult", new 
string[] { "resume" });
            }
            catch (Exception)
            {
                Debug.WriteLine("Resume event error");
            }  
        }

        void GapBrowser_Loaded(object sender, RoutedEventArgs e)
        {
            if (DesignerProperties.IsInDesignTool)
            {
                return;
            }

            // prevents refreshing web control to initial state during pages 
transitions
            if (this.IsBrowserInitialized) return;

            this.domStorageHelper = new DOMStorageHelper(this.CordovaBrowser);

            try
            {

                // Before we possibly clean the ISO-Store, we need to grab our 
generated UUID, so we can rewrite it after.
                string deviceUUID = "";

                using (IsolatedStorageFile appStorage = 
IsolatedStorageFile.GetUserStoreForApplication())
                {
                    try
                    {
                        IsolatedStorageFileStream fileStream = new 
IsolatedStorageFileStream("DeviceID.txt", FileMode.Open, FileAccess.Read, 
appStorage);

                        using (StreamReader reader = new 
StreamReader(fileStream))
                        {
                            deviceUUID = reader.ReadLine();
                        }
                    }
                    catch (Exception /*ex*/)
                    {
                        deviceUUID = Guid.NewGuid().ToString();
                    }

                    Debug.WriteLine("Updating IsolatedStorage for APP:DeviceID 
:: " + deviceUUID);
                    IsolatedStorageFileStream file = new 
IsolatedStorageFileStream("DeviceID.txt", FileMode.Create, FileAccess.Write, 
appStorage);
                    using (StreamWriter writeFile = new StreamWriter(file))
                    {
                        writeFile.WriteLine(deviceUUID);
                        writeFile.Close();
                    }
   
                }

                StreamResourceInfo streamInfo = 
Application.GetResourceStream(new Uri("CordovaSourceDictionary.xml", 
UriKind.Relative));

                if (streamInfo != null)
                {
                    StreamReader sr = new StreamReader(streamInfo.Stream);
                    //This will Read Keys Collection for the xml file

                    XDocument document = XDocument.Parse(sr.ReadToEnd());

                    var files = from results in document.Descendants("FilePath")
                                 select new
                                 {
                                     path =  (string)results.Attribute("Value")
                                 };
                    StreamResourceInfo fileResourceStreamInfo;

                    using (IsolatedStorageFile appStorage = 
IsolatedStorageFile.GetUserStoreForApplication())
                    {

                        foreach (var file in files)
                        {
                            fileResourceStreamInfo = 
Application.GetResourceStream(new Uri(file.path, UriKind.Relative));

                            if (fileResourceStreamInfo != null)
                            {
                                using (BinaryReader br = new 
BinaryReader(fileResourceStreamInfo.Stream))
                                {
                                    byte[] data = 
br.ReadBytes((int)fileResourceStreamInfo.Stream.Length);

                                    string strBaseDir = AppRoot + 
file.path.Substring(0, 
file.path.LastIndexOf(System.IO.Path.DirectorySeparatorChar));

                                    if(!appStorage.DirectoryExists(strBaseDir))
                                    {
                                        //Debug.WriteLine("Creating Directory 
:: " + strBaseDir);
                                        appStorage.CreateDirectory(strBaseDir);
                                    }

                                    // This will truncate/overwrite an existing 
file, or 
                                    using (IsolatedStorageFileStream outFile = 
appStorage.OpenFile(AppRoot + file.path, FileMode.Create))
                                    {
                                        Debug.WriteLine("Writing data for " + 
AppRoot + file.path + " and length = " + data.Length);
                                        using (var writer = new 
BinaryWriter(outFile))
                                        {
                                            writer.Write(data);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                Debug.WriteLine("Failed to write file :: " + 
file.path + " did you forget to add it to the project?");
                            }
                        }
                    }
                }

                CordovaBrowser.Navigate(StartPageUri);
                IsBrowserInitialized = true;
                AttachHardwareButtonHandlers();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception in GapBrowser_Loaded :: {0}", 
ex.Message);
            }
        }

        void AttachHardwareButtonHandlers()
        {
            PhoneApplicationFrame frame = Application.Current.RootVisual as 
PhoneApplicationFrame;
            if (frame != null)
            {
                PhoneApplicationPage page = frame.Content as 
PhoneApplicationPage;
                 
                if (page != null)
                {
                    page.BackKeyPress += new 
EventHandler<CancelEventArgs>(page_BackKeyPress);

                    this.orientationHelper = new 
OrientationHelper(this.CordovaBrowser, page); 

                }
            }
        }

        void page_BackKeyPress(object sender, CancelEventArgs e)
        {
            if (OverrideBackButton)
            {
                try
                {
                    CordovaBrowser.InvokeScript("CordovaCommandResult", new 
string[] { "backbutton" });
                    e.Cancel = true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception while invoking backbutton into 
cordova view: " + ex.Message);
                }
            }
            else
            {
                if (history.Count > 1)
                {
                    Uri current = history.Peek();
                    history.Pop();
                    Uri next = history.Peek();
                    Debug.WriteLine("current = " + current + "   next = " + 
next);
                    int curHash = current.ToString().IndexOf("#");
                    int nextHash = next.ToString().IndexOf("#");
                    if (curHash > 0 && nextHash > 0 && curHash == nextHash)
                    {
                        Debug.WriteLine("doing window.history.back()");
                        IsBackButtonPressed = false;
                        CordovaBrowser.InvokeScript("eval", 
"window.history.back()");
                        if (next.ToString().IndexOf("_wpBackReload") > -1)
                        {
                            CordovaBrowser.InvokeScript("eval", 
"window.location.reload()");
                        }
                    }
                    else
                    {
                        Debug.WriteLine("Doing Navigate");
                        if (next.ToString().IndexOf("_wpBackReload") > -1)
                        {
                            Uri last = history.Last();
                            history.Clear();
                            history.Push(last);
                        }
                        IsBackButtonPressed = true;
                        CordovaBrowser.Navigate(next);
                    }
                    e.Cancel = true;
                }
            }
        }

        void GapBrowser_LoadCompleted(object sender, 
System.Windows.Navigation.NavigationEventArgs e)
        {
            this.CordovaBrowser.Opacity = 1;

            string nativeReady = "(function(){ 
cordova.require('cordova/channel').onNativeReady.fire()})();";

            try
            {
                CordovaBrowser.InvokeScript("execScript", new string[] { 
nativeReady });
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error calling js to fire nativeReady event. 
Did you include cordova-x.x.x.js in your html script tag?");
            }
        }


        void GapBrowser_Navigating(object sender, NavigatingEventArgs e)
        {
            if (!IsBackButtonPressed)
            {
                history.Push(e.Uri);
            }
            else
            {
                IsBackButtonPressed = false;
            }

            Debug.WriteLine("GapBrowser_Navigating to :: " + e.Uri.ToString());
            // TODO: tell any running plugins to stop doing what they are doing.
            // TODO: check whitelist / blacklist
            // NOTE: Navigation can be cancelled by setting :        e.Cancel = 
true;


        }

        /*
         *  This method does the work of routing commands
         *  NotifyEventArgs.Value contains a string passed from JS 
         *  If the command already exists in our map, we will just attempt to 
call the method(action) specified, and pass the args along
         *  Otherwise, we create a new instance of the command, add it to the 
map, and call it ...
         *  This method may also receive JS error messages caught by 
window.onerror, in any case where the commandStr does not appear to be a valid 
command
         *  it is simply output to the debugger output, and the method returns.
         * 
         **/
        void GapBrowser_ScriptNotify(object sender, NotifyEventArgs e)
        {
            string commandStr = e.Value;

            if (commandStr.IndexOf("DOMStorage") == 0)
            {
                this.domStorageHelper.HandleStorageCommand(commandStr);
                return;
            }
            else if (commandStr.IndexOf("Orientation") == 0)
            {
                this.orientationHelper.HandleCommand(commandStr);
                return;
            }

            CordovaCommandCall commandCallParams = 
CordovaCommandCall.Parse(commandStr);

            if (commandCallParams == null)
            {
                // ERROR
                Debug.WriteLine("ScriptNotify :: " + commandStr);
            }
            else if (commandCallParams.Service == "CoreEvents")
            {
                switch (commandCallParams.Action.ToLower())
                {
                    case "overridebackbutton":
                        string args = commandCallParams.Args;
                        this.OverrideBackButton = (args != null && args.Length 
> 0 && args.ToLower() == "true");
                        break;
                }
                if (commandCallParams.Action.ToLower() == "softbackbutton")
                {
                    try
                    {
                        CordovaBrowser.InvokeScript("eval", 
"window.history.back()");
                        history.Pop();
                    }
                    catch (Exception ex)
                    {
                        //do nothing, must have been called from first page, 
not our fault here.
                    }
                }
                if (commandCallParams.Action.ToLower() == "historystackpop")
                {
                    try
                    {
                        history.Pop();
                    }
                    catch (Exception ex)
                    {
                        //do nothing, must have been called from first page, 
not our fault here.
                    }
                }
                if (commandCallParams.Action.ToLower() == "historystackclear")
                {
                    try
                    {
                        history.Clear();
                    }
                    catch (Exception ex)
                    {
                        //do nothing, must have been called from first page, 
not our fault here.
                    }
                }
            }
            else
            {
                //Debug.WriteLine("ProcessCommand :: " + commandStr);
                this.nativeExecution.ProcessCommand(commandCallParams);
            }
        }

        private void GapBrowser_Unloaded(object sender, RoutedEventArgs e)
        {

        }

        private void GapBrowser_NavigationFailed(object sender, 
System.Windows.Navigation.NavigationFailedEventArgs e)
        {
            Debug.WriteLine("GapBrowser_NavigationFailed :: " + 
e.Uri.ToString());
        }

        private void GapBrowser_Navigated(object sender, 
System.Windows.Navigation.NavigationEventArgs e)
        {
            Debug.WriteLine("GapBrowser_Navigated :: " + e.Uri.ToString());
        }

       
    }
}


                
      was (Author: offshorewahoo):
    I wound up modifying CordovaView.xaml.cs in WP7CordovaClassLib.  It turns 
out WP7 apps really need to be able to have more control over the history stack 
in order to comply with Marketplace tech cert requirements.  Here is the source 
I wound up settling on for CordovaView.xaml.cs...  Note the enhancements to 
void GapBrowser_ScriptNotify, and also to void page_BackKeyPress.

/*  
        Licensed under the Apache License, Version 2.0 (the "License");
        you may not use this file except in compliance with the License.
        You may obtain a copy of the License at
        
        http://www.apache.org/licenses/LICENSE-2.0
        
        Unless required by applicable law or agreed to in writing, software
        distributed under the License is distributed on an "AS IS" BASIS,
        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        See the License for the specific language governing permissions and
        limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
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.Shapes;
using Microsoft.Phone.Controls;
using System.IO.IsolatedStorage;
using System.Windows.Resources;
using System.Windows.Interop;
using System.Runtime.Serialization.Json;
using System.IO;
using System.ComponentModel;
using System.Xml.Linq;
using WP7CordovaClassLib.Cordova.Commands;
using System.Diagnostics;
using System.Text;
using WP7CordovaClassLib.Cordova;
using System.Threading;
using Microsoft.Phone.Shell;



namespace WP7CordovaClassLib
{
    public partial class CordovaView : UserControl
    {
       
        /// <summary>
        /// Indicates whether web control has been loaded and no additional 
initialization is needed.
        /// Prevents data clearing during page transitions.
        /// </summary>
        private bool IsBrowserInitialized = false;
        
        /// <summary>
        /// Set when the user attaches a back button handler inside the 
WebBrowser
        /// </summary>
        private bool OverrideBackButton = false;

        /// <summary>
        /// Used for keeping track of our history
        /// </summary>
        private Stack<Uri> history = new Stack<Uri>();
        private bool IsBackButtonPressed = false;


        private static string AppRoot = "/app/";


        /// <summary>
        /// Handles native api calls
        /// </summary>
        private NativeExecution nativeExecution;

        protected DOMStorageHelper domStorageHelper;
        protected OrientationHelper orientationHelper;

        public System.Windows.Controls.Grid _LayoutRoot
        {
            get
            {
                return 
((System.Windows.Controls.Grid)(this.FindName("LayoutRoot")));
            }
        }

        public WebBrowser Browser
        {
            get
            {
                return CordovaBrowser;
            }
        }

        /*
         * Setting StartPageUri only has an effect if called before the view is 
loaded.
         **/
        protected Uri _startPageUri = null;
        public Uri StartPageUri
        {
            get
            {
                if (_startPageUri == null)
                {
                    // default
                    return new Uri( AppRoot + "www/index.html", 
UriKind.Relative);                    
                }
                else
                {
                    return _startPageUri;
                }
            }
            set
            {
                if (!this.IsBrowserInitialized)
                {
                    _startPageUri = value;
                }
            }
        }

        public CordovaView()
        {
            
            InitializeComponent();

            if (DesignerProperties.IsInDesignTool)
            {
                return;
            }


            StartupMode mode = PhoneApplicationService.Current.StartupMode;

            if (mode == StartupMode.Launch)
            {
                PhoneApplicationService service = 
PhoneApplicationService.Current;
                service.Activated += new 
EventHandler<Microsoft.Phone.Shell.ActivatedEventArgs>(AppActivated);
                service.Launching += new 
EventHandler<LaunchingEventArgs>(AppLaunching);
                service.Deactivated += new 
EventHandler<DeactivatedEventArgs>(AppDeactivated);
                service.Closing += new 
EventHandler<ClosingEventArgs>(AppClosing);
            }
            else
            {

            }

            // initializes native execution logic
            this.nativeExecution = new NativeExecution(ref this.CordovaBrowser);
        }

        

        void AppClosing(object sender, ClosingEventArgs e)
        {
            Debug.WriteLine("AppClosing");
        }

        void AppDeactivated(object sender, DeactivatedEventArgs e)
        {
            Debug.WriteLine("AppDeactivated");

            try
            {
                CordovaBrowser.InvokeScript("CordovaCommandResult", new 
string[] { "pause" });
            }
            catch (Exception)
            {
                Debug.WriteLine("Pause event error");
            } 
        }

        void AppLaunching(object sender, LaunchingEventArgs e)
        {
            Debug.WriteLine("AppLaunching");
        }

        void AppActivated(object sender, 
Microsoft.Phone.Shell.ActivatedEventArgs e)
        {
            Debug.WriteLine("AppActivated");
            try
            {
                CordovaBrowser.InvokeScript("CordovaCommandResult", new 
string[] { "resume" });
            }
            catch (Exception)
            {
                Debug.WriteLine("Resume event error");
            }  
        }

        void GapBrowser_Loaded(object sender, RoutedEventArgs e)
        {
            if (DesignerProperties.IsInDesignTool)
            {
                return;
            }

            // prevents refreshing web control to initial state during pages 
transitions
            if (this.IsBrowserInitialized) return;

            this.domStorageHelper = new DOMStorageHelper(this.CordovaBrowser);

            try
            {

                // Before we possibly clean the ISO-Store, we need to grab our 
generated UUID, so we can rewrite it after.
                string deviceUUID = "";

                using (IsolatedStorageFile appStorage = 
IsolatedStorageFile.GetUserStoreForApplication())
                {
                    try
                    {
                        IsolatedStorageFileStream fileStream = new 
IsolatedStorageFileStream("DeviceID.txt", FileMode.Open, FileAccess.Read, 
appStorage);

                        using (StreamReader reader = new 
StreamReader(fileStream))
                        {
                            deviceUUID = reader.ReadLine();
                        }
                    }
                    catch (Exception /*ex*/)
                    {
                        deviceUUID = Guid.NewGuid().ToString();
                    }

                    Debug.WriteLine("Updating IsolatedStorage for APP:DeviceID 
:: " + deviceUUID);
                    IsolatedStorageFileStream file = new 
IsolatedStorageFileStream("DeviceID.txt", FileMode.Create, FileAccess.Write, 
appStorage);
                    using (StreamWriter writeFile = new StreamWriter(file))
                    {
                        writeFile.WriteLine(deviceUUID);
                        writeFile.Close();
                    }
   
                }

                StreamResourceInfo streamInfo = 
Application.GetResourceStream(new Uri("CordovaSourceDictionary.xml", 
UriKind.Relative));

                if (streamInfo != null)
                {
                    StreamReader sr = new StreamReader(streamInfo.Stream);
                    //This will Read Keys Collection for the xml file

                    XDocument document = XDocument.Parse(sr.ReadToEnd());

                    var files = from results in document.Descendants("FilePath")
                                 select new
                                 {
                                     path =  (string)results.Attribute("Value")
                                 };
                    StreamResourceInfo fileResourceStreamInfo;

                    using (IsolatedStorageFile appStorage = 
IsolatedStorageFile.GetUserStoreForApplication())
                    {

                        foreach (var file in files)
                        {
                            fileResourceStreamInfo = 
Application.GetResourceStream(new Uri(file.path, UriKind.Relative));

                            if (fileResourceStreamInfo != null)
                            {
                                using (BinaryReader br = new 
BinaryReader(fileResourceStreamInfo.Stream))
                                {
                                    byte[] data = 
br.ReadBytes((int)fileResourceStreamInfo.Stream.Length);

                                    string strBaseDir = AppRoot + 
file.path.Substring(0, 
file.path.LastIndexOf(System.IO.Path.DirectorySeparatorChar));

                                    if(!appStorage.DirectoryExists(strBaseDir))
                                    {
                                        //Debug.WriteLine("Creating Directory 
:: " + strBaseDir);
                                        appStorage.CreateDirectory(strBaseDir);
                                    }

                                    // This will truncate/overwrite an existing 
file, or 
                                    using (IsolatedStorageFileStream outFile = 
appStorage.OpenFile(AppRoot + file.path, FileMode.Create))
                                    {
                                        Debug.WriteLine("Writing data for " + 
AppRoot + file.path + " and length = " + data.Length);
                                        using (var writer = new 
BinaryWriter(outFile))
                                        {
                                            writer.Write(data);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                Debug.WriteLine("Failed to write file :: " + 
file.path + " did you forget to add it to the project?");
                            }
                        }
                    }
                }

                CordovaBrowser.Navigate(StartPageUri);
                IsBrowserInitialized = true;
                AttachHardwareButtonHandlers();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception in GapBrowser_Loaded :: {0}", 
ex.Message);
            }
        }

        void AttachHardwareButtonHandlers()
        {
            PhoneApplicationFrame frame = Application.Current.RootVisual as 
PhoneApplicationFrame;
            if (frame != null)
            {
                PhoneApplicationPage page = frame.Content as 
PhoneApplicationPage;
                 
                if (page != null)
                {
                    page.BackKeyPress += new 
EventHandler<CancelEventArgs>(page_BackKeyPress);

                    this.orientationHelper = new 
OrientationHelper(this.CordovaBrowser, page); 

                }
            }
        }

        void page_BackKeyPress(object sender, CancelEventArgs e)
        {
            if (OverrideBackButton)
            {
                try
                {
                    CordovaBrowser.InvokeScript("CordovaCommandResult", new 
string[] { "backbutton" });
                    e.Cancel = true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception while invoking backbutton into 
cordova view: " + ex.Message);
                }
            }
            else
            {
                if (history.Count > 1)
                {
                    Uri current = history.Peek();
                    history.Pop();
                    Uri next = history.Peek();
                    IsBackButtonPressed = true;
                    bool doHistory = false;
                    if (current.ToString().IndexOf("#") > 0 && 
next.ToString().IndexOf("#") > 0)
                    {
                        if (current.ToString().Substring(0, 
current.ToString().IndexOf("#")) == next.ToString().Substring(0, 
next.ToString().IndexOf("#")))
                        {
                            doHistory = true;
                        }
                    }
                    if (doHistory)
                    {
                        CordovaBrowser.InvokeScript("eval", 
"window.history.back()");
                        CordovaBrowser.InvokeScript("eval", 
"window.location.reload()");
                    }
                    else
                    {
                        CordovaBrowser.Navigate(next);
                    }
                    e.Cancel = true;
                }
            }
        }

        void GapBrowser_LoadCompleted(object sender, 
System.Windows.Navigation.NavigationEventArgs e)
        {
            this.CordovaBrowser.Opacity = 1;

            string nativeReady = "(function(){ 
cordova.require('cordova/channel').onNativeReady.fire()})();";

            try
            {
                CordovaBrowser.InvokeScript("execScript", new string[] { 
nativeReady });
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error calling js to fire nativeReady event. 
Did you include cordova-x.x.x.js in your html script tag?");
            }
        }


        void GapBrowser_Navigating(object sender, NavigatingEventArgs e)
        {
            if (!IsBackButtonPressed)
            {
                history.Push(e.Uri);
            }
            else
            {
                IsBackButtonPressed = false;
            }

            Debug.WriteLine("GapBrowser_Navigating to :: " + e.Uri.ToString());
            // TODO: tell any running plugins to stop doing what they are doing.
            // TODO: check whitelist / blacklist
            // NOTE: Navigation can be cancelled by setting :        e.Cancel = 
true;


        }

        /*
         *  This method does the work of routing commands
         *  NotifyEventArgs.Value contains a string passed from JS 
         *  If the command already exists in our map, we will just attempt to 
call the method(action) specified, and pass the args along
         *  Otherwise, we create a new instance of the command, add it to the 
map, and call it ...
         *  This method may also receive JS error messages caught by 
window.onerror, in any case where the commandStr does not appear to be a valid 
command
         *  it is simply output to the debugger output, and the method returns.
         * 
         **/
        void GapBrowser_ScriptNotify(object sender, NotifyEventArgs e)
        {
            string commandStr = e.Value;

            if (commandStr.IndexOf("DOMStorage") == 0)
            {
                this.domStorageHelper.HandleStorageCommand(commandStr);
                return;
            }
            else if (commandStr.IndexOf("Orientation") == 0)
            {
                this.orientationHelper.HandleCommand(commandStr);
                return;
            }

            CordovaCommandCall commandCallParams = 
CordovaCommandCall.Parse(commandStr);

            if (commandCallParams == null)
            {
                // ERROR
                Debug.WriteLine("ScriptNotify :: " + commandStr);
            }
            else if (commandCallParams.Service == "CoreEvents")
            {
                switch (commandCallParams.Action.ToLower())
                {
                    case "overridebackbutton":
                        string args = commandCallParams.Args;
                        this.OverrideBackButton = (args != null && args.Length 
> 0 && args.ToLower() == "true");
                        break;
                }
                if (commandCallParams.Action.ToLower() == "softbackbutton")
                {
                    try
                    {
                        CordovaBrowser.InvokeScript("eval", 
"window.history.back()");
                        history.Pop();
                    }
                    catch (Exception ex)
                    {
                        //do nothing, must have been called from first page, 
not our fault here.
                    }
                }
                if (commandCallParams.Action.ToLower() == "historystackpop")
                {
                    try
                    {
                        history.Pop();
                    }
                    catch (Exception ex)
                    {
                        //do nothing, must have been called from first page, 
not our fault here.
                    }
                }
                if (commandCallParams.Action.ToLower() == "historystackclear")
                {
                    try
                    {
                        history = new Stack<Uri>();
                    }
                    catch (Exception ex)
                    {
                        //do nothing, must have been called from first page, 
not our fault here.
                    }
                }
            }
            else
            {
                //Debug.WriteLine("ProcessCommand :: " + commandStr);
                this.nativeExecution.ProcessCommand(commandCallParams);
            }
        }

        private void GapBrowser_Unloaded(object sender, RoutedEventArgs e)
        {

        }

        private void GapBrowser_NavigationFailed(object sender, 
System.Windows.Navigation.NavigationFailedEventArgs e)
        {
            Debug.WriteLine("GapBrowser_NavigationFailed :: " + 
e.Uri.ToString());
        }

        private void GapBrowser_Navigated(object sender, 
System.Windows.Navigation.NavigationEventArgs e)
        {
            Debug.WriteLine("GapBrowser_Navigated :: " + e.Uri.ToString());
        }

       
    }
}

                  
> WP7 Certification and the Back Button
> -------------------------------------
>
>                 Key: CB-520
>                 URL: https://issues.apache.org/jira/browse/CB-520
>             Project: Apache Callback
>          Issue Type: Bug
>          Components: WP7
>    Affects Versions: 1.6.1
>         Environment: VS.NET 2010 and WP7.1 emulator
>            Reporter: Alan Neveu
>            Assignee: Jesse MacFadyen
>            Priority: Minor
>
> I tried submitting my PG 1.5 app to the Windows Marketplace and it was 
> rejected due to WP7's requirements for the Back Button. I upgraded to PG 
> 1.6.1 and I am inspecting how it works with the hardware back button.  It 
> seems to work much better, but my app is designed so that it has a soft back 
> button in the app in various places, and on WP7 the user can always tap the 
> hardware back button.  I am trying to use navigator.app.historyBack and it 
> appears to work, but it does something slightly different than actually 
> tapping the hardware back button does.  I have also tried using 
> window.history.back and that works different yet.  I am using JQueryMobile 
> 1.1.0 and so I wind up doing quite a lot of $.mobile.changePage calls to 
> #Page id's, and because I use multiple .html files I also need to do some 
> rel="external" links or window.location.href= calls.  I think my needs are 
> similar or the same as those of other WP7 developers.  Here is what currently 
> happens with PG 1.6.1 in a simple Page1/Page2 JQueryMobile app when using the 
> hardware back button versus using navigator.app.historyBack, vs. 
> window.history.back:
> SCENARIO #1 - using hardware BackButton only
> Page 1 links to Page 2 using $.mobile.changePage("#Page2");
> BackButton tap - goes back to Page1 but page is requested again and reloaded 
> from scratch which is slow and the user loses any form data they had entered.
> BackButton tap - exits app (great!)
> SCENARIO #2 - hardware BackButton and navigator.app.backHistory
> Page 1 links to Page 2 using $.mobile.changePage("#Page2");
> navigator.app.backHistory(); goes back to Page1 served from cache, which is 
> fast and form data is preserved.
> BackButton tap: nothing happens
> BackButton tap: Page1 is reloaded from scratch
> BackButton tap: exits app
> SCENARIO #3 - hardware backButton and window.history.back
> Page 1 links to Page 2 using $.mobile.changePage("#Page2");
> window.history.back(); goes back to Page1 served from cache.
> BackButton tap: Page1 is reloaded from scratch (DOH!)
> BackButton tap: exits app
> My Observations:
> 1) The hardware back button does not use the cached page - it 
> reloads/re-requests the page. This is kind of a drag but I think we have to 
> just go with this because it is the behavior that the Marketplace testers 
> will be expecting and validating.
> 2) window.history.back() is giving better results than 
> navigator.app.backHistory, but still not the same as the hardware back 
> button. I think apps will fail Marketplace certification if they use either 
> of these approaches for soft back buttons.
> 3) When going back to an external page (as opposed to a JQueryMobile 
> #pageID), window.history.back works but navigator.app.backHistory does not 
> seem to do anything at all.  I say window.history.back "works" but it is 
> still the same result as in Scenario #3 above, which is not good.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: 
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira


Reply via email to