CB-8139 WP8. Fix callback for plugins with native ui (capture, contactPicker, BarcodeScanner, other)

Unload event could not be used to detect when CordovaView is not used anymore. For example, this event is triggered when we execute command that shows some native elements on new page and then we return back. In this case Unloaded event is called but, but control state is preserved and we should continue to use that Cordova view instance.

This commit changes the following:
1. Allows command instances to be garbage collected => fixes corresponding memory leak so that NativeExecution is no more required to call DetachHandlers for each command. This fixes  CB-8139.
2. Use Loaded and Unloaded events to add/remove handlers for native events; this makes it possible for GC to destroy CordovaView when it is not required anymore
diff --git a/template/cordovalib/ConsoleHelper.cs b/template/cordovalib/ConsoleHelper.cs
index 3443821..72edfb2 100644
--- a/template/cordovalib/ConsoleHelper.cs
+++ b/template/cordovalib/ConsoleHelper.cs
@@ -38,13 +38,6 @@
             {
             }
 
-            if (!hasListener)
-            {
-                PhoneApplicationService.Current.Closing += OnServiceClosing;
-                hasListener = true;
-            }
-
-
             string script = @"(function(win) {
         function exec(msg) { window.external.Notify('ConsoleLog/' + msg); }
         var cons = win.console = win.console || {};
@@ -71,15 +64,6 @@
             }
         }
 
-        public void DetachHandler()
-        {
-            if (hasListener)
-            {
-                PhoneApplicationService.Current.Closing -= OnServiceClosing;
-                hasListener = false;
-            }
-        }
-
         public bool HandleCommand(string commandStr)
         {
             string output = commandStr.Substring("ConsoleLog/".Length);
@@ -96,5 +80,15 @@
             return true;
         }
 
+        public void AttachNativeHandlers()
+        {
+            PhoneApplicationService.Current.Closing += OnServiceClosing;
+        }
+
+        public void DetachNativeHandlers()
+        {
+            PhoneApplicationService.Current.Closing -= OnServiceClosing;
+        }
+
     }
 }
diff --git a/template/cordovalib/CordovaView.xaml.cs b/template/cordovalib/CordovaView.xaml.cs
index 5e790a3..4c509e0 100644
--- a/template/cordovalib/CordovaView.xaml.cs
+++ b/template/cordovalib/CordovaView.xaml.cs
@@ -136,21 +136,7 @@
                 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
-            {
-
-            }
+            Debug.WriteLine("Created new CordovaView instance");
 
             // initializes native execution logic
             configHandler = new ConfigHandler();
@@ -270,6 +256,18 @@
 
         void CordovaBrowser_Loaded(object sender, RoutedEventArgs e)
         {
+          
+            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);
+
+            foreach (IBrowserDecorator iBD in browserDecorators.Values)
+            {
+                iBD.AttachNativeHandlers();
+            }
+
 
             this.bmHelper.ScrollDisabled = this.DisableBouncyScrolling;
 
@@ -322,6 +320,20 @@
             }
         }
 
+        private void CordovaBrowser_Unloaded(object sender, RoutedEventArgs e)
+        {
+            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);
+
+            foreach (IBrowserDecorator iBD in browserDecorators.Values)
+            {
+                iBD.DetachNativeHandlers();
+            }
+        }
+
         void AttachHardwareButtonHandlers()
         {
             PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
@@ -524,21 +536,6 @@
             }
         }
 
-        private void CordovaBrowser_Unloaded(object sender, RoutedEventArgs e)
-        {
-            IBrowserDecorator console;
-            if (browserDecorators.TryGetValue("ConsoleLog", out console))
-            {
-                ((ConsoleHelper)console).DetachHandler();
-            }
-
-            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);
-        }
-
         private void CordovaBrowser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
         {
             Debug.WriteLine("CordovaBrowser_NavigationFailed :: " + e.Uri.ToString());
@@ -546,10 +543,10 @@
 
         private void CordovaBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
         {
-           foreach(IBrowserDecorator iBD in browserDecorators.Values)
-           {
-               iBD.InjectScript();
-           }
+            foreach (IBrowserDecorator iBD in browserDecorators.Values)
+            {
+                iBD.InjectScript();
+            }
         }
 
         /// <summary>
@@ -576,5 +573,10 @@
                               (byte)(argb & 0xff));
             return clr;
         }
+
+        ~CordovaView()
+        {
+            Debug.WriteLine("CordovaView is destroyed");
+        }
     }
 }
diff --git a/template/cordovalib/IBrowserDecorator.cs b/template/cordovalib/IBrowserDecorator.cs
index bc1dbee..8425865 100644
--- a/template/cordovalib/IBrowserDecorator.cs
+++ b/template/cordovalib/IBrowserDecorator.cs
@@ -26,5 +26,7 @@
         WebBrowser Browser { get; set; }
         void InjectScript();
         bool HandleCommand(string cmd);
+        void AttachNativeHandlers();
+        void DetachNativeHandlers();
     }
 }
diff --git a/template/cordovalib/NativeExecution.cs b/template/cordovalib/NativeExecution.cs
index 18ca910..fe35aea 100644
--- a/template/cordovalib/NativeExecution.cs
+++ b/template/cordovalib/NativeExecution.cs
@@ -52,21 +52,6 @@
 
             this.webBrowser = browser;
             this.commands = new List<BaseCommand>();
-            webBrowser.Unloaded += webBrowser_Unloaded;
-        }
-
-        /// <summary>
-        /// Detaches event handlers to prevent memory leak on page navigation
-        /// </summary>
-        void webBrowser_Unloaded(object sender, RoutedEventArgs e)
-        {
-            for (int i = commands.Count - 1; i >= 0; i--)
-            {
-                if (commands[i] != null)
-                {
-                    commands[i].DetachHandlers();
-                }
-            }
         }
 
         /// <summary>
@@ -115,6 +100,12 @@
                     return;
                 }
 
+                // TODO: consider removing custom script functionality at all since we already marked it as absolute (see BaseCommand)
+                EventHandler<ScriptCallback> OnCustomScriptHandler = delegate(object o, ScriptCallback script)
+                {
+                    this.InvokeScriptCallback(script);
+                };
+
                 EventHandler<PluginResult> OnCommandResultHandler = delegate(object o, PluginResult res)
                 {
                     if (res.CallbackId == null || res.CallbackId == commandCallParams.CallbackId)
@@ -123,6 +114,7 @@
                         if (!res.KeepCallback)
                         {
                             bc.RemoveResultHandler(commandCallParams.CallbackId);
+                            bc.OnCustomScript -= OnCustomScriptHandler;
                         }
                     }
                 };
@@ -130,11 +122,6 @@
                 //bc.OnCommandResult += OnCommandResultHandler;
                 bc.AddResultHandler(commandCallParams.CallbackId, OnCommandResultHandler);
 
-                EventHandler<ScriptCallback> OnCustomScriptHandler = delegate(object o, ScriptCallback script)
-                {
-                    this.InvokeScriptCallback(script);
-                };
-
                 bc.OnCustomScript += OnCustomScriptHandler;
 
                 ThreadStart methodInvokation = () =>
diff --git a/template/cordovalib/OrientationHelper.cs b/template/cordovalib/OrientationHelper.cs
index 299f9dd..0ec32fe 100644
--- a/template/cordovalib/OrientationHelper.cs
+++ b/template/cordovalib/OrientationHelper.cs
@@ -125,6 +125,16 @@
             // No commands are currently accepted.
             return true;
         }
+
+        public void AttachNativeHandlers()
+        {
+            // nothing todo
+        }
+
+        public void DetachNativeHandlers()
+        {
+            // nothing to do
+        }
     }
 
 
diff --git a/template/cordovalib/XHRHelper.cs b/template/cordovalib/XHRHelper.cs
index 35913eb..1d72367 100644
--- a/template/cordovalib/XHRHelper.cs
+++ b/template/cordovalib/XHRHelper.cs
@@ -342,5 +342,15 @@
 
             return false;
         }
+
+        public void AttachNativeHandlers()
+        {
+            // nothing todo
+        }
+
+        public void DetachNativeHandlers()
+        {
+            // nothing to do
+        }
     }
 }