| /* |
| 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> |
| /// Sentinal to keep track of page changes as a result of the hardware back button |
| /// Set to false when the back-button is pressed, which calls js window.history.back() |
| /// If the page changes as a result of the back button the event is cancelled. |
| /// </summary> |
| private bool PageDidChange = false; |
| |
| private static string AppRoot = "/app/"; |
| |
| |
| /// <summary> |
| /// Handles native api calls |
| /// </summary> |
| private NativeExecution nativeExecution; |
| |
| protected BrowserMouseHelper bmHelper; |
| |
| 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); |
| this.bmHelper = new BrowserMouseHelper(ref this.CordovaBrowser); |
| } |
| |
| |
| |
| void AppClosing(object sender, ClosingEventArgs e) |
| { |
| Debug.WriteLine("AppClosing"); |
| } |
| |
| void AppDeactivated(object sender, DeactivatedEventArgs e) |
| { |
| Debug.WriteLine("INFO: AppDeactivated"); |
| |
| try |
| { |
| CordovaBrowser.InvokeScript("CordovaCommandResult", new string[] { "pause" }); |
| } |
| catch (Exception) |
| { |
| Debug.WriteLine("ERROR: Pause event error"); |
| } |
| } |
| |
| void AppLaunching(object sender, LaunchingEventArgs e) |
| { |
| Debug.WriteLine("INFO: AppLaunching"); |
| } |
| |
| void AppActivated(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e) |
| { |
| Debug.WriteLine("INFO: AppActivated"); |
| try |
| { |
| CordovaBrowser.InvokeScript("CordovaCommandResult", new string[] { "resume" }); |
| } |
| catch (Exception) |
| { |
| Debug.WriteLine("ERROR: 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("INFO: 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("INFO: Writing data for " + AppRoot + file.path + " and length = " + data.Length); |
| using (var writer = new BinaryWriter(outFile)) |
| { |
| writer.Write(data); |
| } |
| } |
| } |
| } |
| else |
| { |
| Debug.WriteLine("ERROR: 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("ERROR: 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 |
| { |
| try |
| { |
| PageDidChange = false; |
| |
| Uri uriBefore = this.Browser.Source; |
| // calling js history.back with result in a page change if history was valid. |
| CordovaBrowser.InvokeScript("eval", new string[] { "(function(){window.history.back();})()" }); |
| |
| Uri uriAfter = this.Browser.Source; |
| |
| e.Cancel = PageDidChange || (uriBefore != uriAfter); |
| } |
| catch (Exception) |
| { |
| e.Cancel = false; // exit the app ... ? |
| } |
| } |
| } |
| |
| void GapBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e) |
| { |
| 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?"); |
| } |
| |
| if (this.CordovaBrowser.Opacity < 1) |
| { |
| this.CordovaBrowser.Opacity = 1; |
| RotateIn.Begin(); |
| } |
| } |
| |
| |
| void GapBrowser_Navigating(object sender, NavigatingEventArgs e) |
| { |
| this.PageDidChange = true; |
| // 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 arg0 = WP7CordovaClassLib.Cordova.JSON.JsonHelper.Deserialize<string[]>(commandCallParams.Args)[0]; |
| this.OverrideBackButton = (arg0 != null && arg0.Length > 0 && arg0.ToLower() == "true"); |
| break; |
| } |
| } |
| else |
| { |
| 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()); |
| } |
| |
| |
| } |
| } |