Return-Path: X-Original-To: apmail-cordova-commits-archive@www.apache.org Delivered-To: apmail-cordova-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id DBD43D281 for ; Thu, 23 May 2013 21:58:02 +0000 (UTC) Received: (qmail 99162 invoked by uid 500); 23 May 2013 21:58:01 -0000 Delivered-To: apmail-cordova-commits-archive@cordova.apache.org Received: (qmail 99099 invoked by uid 500); 23 May 2013 21:58:00 -0000 Mailing-List: contact commits-help@cordova.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cordova.apache.org Delivered-To: mailing list commits@cordova.apache.org Received: (qmail 98626 invoked by uid 99); 23 May 2013 21:58:00 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 23 May 2013 21:58:00 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id EF0A1646C; Thu, 23 May 2013 21:57:59 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: braden@apache.org To: commits@cordova.apache.org Date: Thu, 23 May 2013 21:58:24 -0000 Message-Id: In-Reply-To: <2fbd752b392b47399f2f6b051c5b5a22@git.apache.org> References: <2fbd752b392b47399f2f6b051c5b5a22@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [27/50] Add WP7 and WP8 platform files. http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/CordovaCommandCall.cs ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/CordovaCommandCall.cs b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaCommandCall.cs new file mode 100644 index 0000000..810f5e2 --- /dev/null +++ b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaCommandCall.cs @@ -0,0 +1,98 @@ +/* + 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.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Ink; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using System.Linq; +using System.Collections.Generic; + +namespace WPCordovaClassLib.Cordova +{ + /// + /// Represents Cordova native command call: action callback, etc + /// + public class CordovaCommandCall + { + public String Service { get; private set; } + public String Action { get; private set; } + public String CallbackId { get; private set; } + public String Args { get; private set; } + + /// + /// Retrieves command call parameters and creates wrapper for them + /// + /// Command string in the form 'service/action/callback/args' + /// New class instance or null of string does not represent Cordova command + public static CordovaCommandCall Parse(string commandStr) + { + if (string.IsNullOrEmpty(commandStr)) + { + return null; + } + + string[] split = commandStr.Split('/'); + if (split.Length < 3) + { + return null; + } + + CordovaCommandCall commandCallParameters = new CordovaCommandCall(); + commandCallParameters.Service = split[0]; + commandCallParameters.Action = split[1]; + commandCallParameters.CallbackId = split[2]; + + try + { + string arg = split.Length <= 3 ? "[]" : String.Join("/", split.Skip(3)); + if (!arg.StartsWith("[")) // save the exception + { + arg = string.Format("[{0}]", arg); + } + List args = JSON.JsonHelper.Deserialize>(arg); + args.Add(commandCallParameters.CallbackId); + commandCallParameters.Args = JSON.JsonHelper.Serialize(args.ToArray()); + } + catch (Exception) + { + return null; + } + // sanity check for illegal names + // was failing with :: + // CordovaCommandResult :: 1, Device1, {"status":1,"message":"{\"name\":\"XD..... + if (commandCallParameters.Service.IndexOfAny(new char[] { '@', ':', ',', '!', ' ' }) > -1) + { + return null; + } + + return commandCallParameters; + } + + + /// + /// Private ctr to disable class creation. + /// New class instance must be initialized via CordovaCommandCall.Parse static method. + /// + private CordovaCommandCall() { } + + + } +} http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml new file mode 100644 index 0000000..b993d97 --- /dev/null +++ b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml.cs ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml.cs b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml.cs new file mode 100644 index 0000000..f6584a8 --- /dev/null +++ b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml.cs @@ -0,0 +1,485 @@ +/* + 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 WPCordovaClassLib.Cordova.Commands; +using System.Diagnostics; +using System.Text; +using WPCordovaClassLib.Cordova; +using System.Threading; +using Microsoft.Phone.Shell; +using WPCordovaClassLib.Cordova.JSON; +using WPCordovaClassLib.CordovaLib; + + + +namespace WPCordovaClassLib +{ + public partial class CordovaView : UserControl + { + + /// + /// Indicates whether web control has been loaded and no additional initialization is needed. + /// Prevents data clearing during page transitions. + /// + private bool IsBrowserInitialized = false; + + /// + /// Set when the user attaches a back button handler inside the WebBrowser + /// + private bool OverrideBackButton = false; + + /// + /// Sentinel 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. + /// + private bool PageDidChange = false; + + private static string AppRoot = "/app/"; + + + /// + /// Handles native api calls + /// + private NativeExecution nativeExecution; + + protected BrowserMouseHelper bmHelper; + + protected DOMStorageHelper domStorageHelper; + protected OrientationHelper orientationHelper; + + private ConfigHandler configHandler; + + 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(AppActivated); + service.Launching += new EventHandler(AppLaunching); + service.Deactivated += new EventHandler(AppDeactivated); + service.Closing += new EventHandler(AppClosing); + } + else + { + + } + + configHandler = new ConfigHandler(); + configHandler.LoadAppPackageConfig(); + + // initializes native execution logic + nativeExecution = new NativeExecution(ref this.CordovaBrowser); + 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("eval", new string[] { "cordova.fireDocumentEvent('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("eval", new string[] { "cordova.fireDocumentEvent('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(page_BackKeyPress); + + this.orientationHelper = new OrientationHelper(this.CordovaBrowser, page); + + } + } + } + + void page_BackKeyPress(object sender, CancelEventArgs e) + { + + if (OverrideBackButton) + { + try + { + CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('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("eval", 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) + { + if (!configHandler.URLIsAllowed(e.Uri.ToString())) + { + e.Cancel = true; + return; + } + + this.PageDidChange = true; + // Debug.WriteLine("GapBrowser_Navigating to :: " + e.Uri.ToString()); + this.nativeExecution.ResetAllCommands(); + + // 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 = JsonHelper.Deserialize(commandCallParams.Args)[0]; + this.OverrideBackButton = (arg0 != null && arg0.Length > 0 && arg0.ToLower() == "true"); + break; + } + } + else + { + if (configHandler.IsPluginAllowed(commandCallParams.Service)) + { + nativeExecution.ProcessCommand(commandCallParams); + } + else + { + Debug.WriteLine("Error::Plugin not allowed in config.xml. " + commandCallParams.Service); + } + } + } + + public void LoadPage(string url) + { + try + { + Uri newLoc = new Uri(url,UriKind.RelativeOrAbsolute); + CordovaBrowser.Navigate(newLoc); + } + catch(Exception) + { + + } + } + + 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()); + } + + + } +} http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/DOMStorageHelper.cs ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/DOMStorageHelper.cs b/lib/cordova-wp7/templates/standalone/cordovalib/DOMStorageHelper.cs new file mode 100644 index 0000000..f57bae4 --- /dev/null +++ b/lib/cordova-wp7/templates/standalone/cordovalib/DOMStorageHelper.cs @@ -0,0 +1,145 @@ +/* + 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.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Ink; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using System.IO.IsolatedStorage; +using System.Collections.Generic; +using Microsoft.Phone.Controls; +using System.Linq; +using WPCordovaClassLib.Cordova.JSON; + +/* + * Translates DOMStorage API between JS and Isolated Storage + * Missing pieces : QUOTA_EXCEEDED_ERR + StorageEvent + * */ + +namespace WPCordovaClassLib +{ + public class DOMStorageHelper + { + protected WebBrowser webBrowser1; + + public DOMStorageHelper(WebBrowser gapBrowser) + { + this.webBrowser1 = gapBrowser; + // always clear session at creation + UserSettings["sessionStorage"] = new Dictionary(); + + if (!UserSettings.Contains("localStorage")) + { + UserSettings["localStorage"] = new Dictionary(); + UserSettings.Save(); + } + Application.Current.Exit += new EventHandler(OnAppExit); + } + + void OnAppExit(object sender, EventArgs e) + { + UserSettings.Remove("sessionStorage"); + UserSettings.Save(); + } + + protected IsolatedStorageSettings UserSettings + { + get + { + return IsolatedStorageSettings.ApplicationSettings; + } + } + + protected Dictionary getStorageByType(string type) + { + if (!UserSettings.Contains(type)) + { + UserSettings[type] = new Dictionary(); + UserSettings.Save(); + } + return UserSettings[type] as Dictionary; + } + + + public void HandleStorageCommand(string commandStr) + { + + string[] split = commandStr.Split('/'); + if (split.Length > 3) + { + string api = split[0]; + string type = split[1]; // localStorage || sessionStorage + string command = split[2]; + string param = split[3]; + + Dictionary currentStorage = getStorageByType(type); + + switch (command) + { + case "get": + { + + if (currentStorage.Keys.Contains(param)) + { + string value = currentStorage[param]; + webBrowser1.InvokeScript("execScript", "window." + type + ".onResult('" + param + "','" + value + "');"); + } + else + { + webBrowser1.InvokeScript("execScript", "window." + type + ".onResult('" + param + "');"); + } + + } + break; + case "load": + { + string[] keys = currentStorage.Keys.ToArray(); + string jsonString = JsonHelper.Serialize(keys); + string callbackJS = "window." + type + ".onKeysChanged('" + jsonString + "');"; + webBrowser1.InvokeScript("execScript", callbackJS); + } + break; + case "set": + { + // TODO: check that length is not out of bounds + currentStorage[param] = split[4]; + UserSettings.Save(); + string[] keys = currentStorage.Keys.ToArray(); + string jsonString = JsonHelper.Serialize(keys); + string callbackJS = "window." + type + ".onKeysChanged('" + jsonString + "');"; + webBrowser1.InvokeScript("execScript", callbackJS); + } + break; + case "remove": + currentStorage.Remove(param); + UserSettings.Save(); + break; + case "clear": + currentStorage = new Dictionary(); + UserSettings[type] = currentStorage; + UserSettings.Save(); + break; + } + + } + + } + } +} http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/JSON/JsonHelper.cs ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/JSON/JsonHelper.cs b/lib/cordova-wp7/templates/standalone/cordovalib/JSON/JsonHelper.cs new file mode 100644 index 0000000..44511f6 --- /dev/null +++ b/lib/cordova-wp7/templates/standalone/cordovalib/JSON/JsonHelper.cs @@ -0,0 +1,97 @@ +/* + 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.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Ink; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using System.Runtime.Serialization.Json; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace WPCordovaClassLib.Cordova.JSON +{ + /// + /// Provides JSON serialization/deserialization functionality. + /// + public static class JsonHelper + { + /// + /// Serializes object to JSON string representation + /// + /// object to serialize + /// JSON representation of the object. Returns 'null' string for null passed as argument + public static string Serialize(object obj) + { + if (obj == null) + { + return "null"; + } + + DataContractJsonSerializer ser = new DataContractJsonSerializer(obj.GetType()); + + MemoryStream ms = new MemoryStream(); + ser.WriteObject(ms, obj); + + ms.Position = 0; + + string json = String.Empty; + + using (StreamReader sr = new StreamReader(ms)) + { + json = sr.ReadToEnd(); + } + + ms.Close(); + + return json; + + } + + /// + /// Parses json string to object instance + /// + /// type of the object + /// json string representation of the object + /// Deserialized object instance + public static T Deserialize(string json) + { + DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T)); + object result = null; + try + { + using (MemoryStream mem = new MemoryStream(Encoding.UTF8.GetBytes(json))) + { + result = deserializer.ReadObject(mem); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + Debug.WriteLine("Failed to deserialize " + typeof(T) + " with JSON value :: " + json); + } + + return (T)result; + + } + } +} http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/NativeExecution.cs ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/NativeExecution.cs b/lib/cordova-wp7/templates/standalone/cordovalib/NativeExecution.cs new file mode 100644 index 0000000..af6b207 --- /dev/null +++ b/lib/cordova-wp7/templates/standalone/cordovalib/NativeExecution.cs @@ -0,0 +1,246 @@ +/* + 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.Diagnostics; +using System.Threading; +using Microsoft.Devices; +using Microsoft.Phone.Controls; +using WPCordovaClassLib.Cordova.Commands; +using System.Windows; + +namespace WPCordovaClassLib.Cordova +{ + /// + /// Implements logic to execute native command and return result back. + /// All commands are executed asynchronous. + /// + public class NativeExecution + { + /// + /// Reference to web part where application is hosted + /// + private readonly WebBrowser webBrowser; + + /// + /// Creates new instance of a NativeExecution class. + /// + /// Reference to web part where application is hosted + public NativeExecution(ref WebBrowser browser) + { + if (browser == null) + { + throw new ArgumentNullException("browser"); + } + + this.webBrowser = browser; + } + + /// + /// Returns where application is running on emulator + /// + /// True if running on emulator, otherwise False + public static bool IsRunningOnEmulator() + { + return Microsoft.Devices.Environment.DeviceType == DeviceType.Emulator; + } + + public void ResetAllCommands() + { + CommandFactory.ResetAllCommands(); + } + + public void AutoLoadCommand(string commandService) + { + BaseCommand bc = CommandFactory.CreateByServiceName(commandService); + if (bc != null) + { + bc.OnInit(); + } + + } + + /// + /// Executes command and returns result back. + /// + /// Command to execute + public void ProcessCommand(CordovaCommandCall commandCallParams) + { + + if (commandCallParams == null) + { + throw new ArgumentNullException("commandCallParams"); + } + + try + { + BaseCommand bc = CommandFactory.CreateByServiceName(commandCallParams.Service); + + if (bc == null) + { + this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION)); + return; + } + + EventHandler OnCommandResultHandler = delegate(object o, PluginResult res) + { + if (res.CallbackId == null || res.CallbackId == commandCallParams.CallbackId) + { + this.OnCommandResult(commandCallParams.CallbackId, res); + if (!res.KeepCallback) + { + bc.RemoveResultHandler(commandCallParams.CallbackId); + } + } + }; + + //bc.OnCommandResult += OnCommandResultHandler; + bc.AddResultHandler(commandCallParams.CallbackId, OnCommandResultHandler); + + EventHandler OnCustomScriptHandler = delegate(object o, ScriptCallback script) + { + this.InvokeScriptCallback(script); + }; + + bc.OnCustomScript += OnCustomScriptHandler; + + ThreadStart methodInvokation = () => + { + try + { + bc.InvokeMethodNamed(commandCallParams.CallbackId,commandCallParams.Action, commandCallParams.Args); + } + catch (Exception ex) + { + Debug.WriteLine("ERROR: Exception in ProcessCommand :: " + ex.Message); + bc.RemoveResultHandler(commandCallParams.CallbackId); + bc.OnCustomScript -= OnCustomScriptHandler; + + Debug.WriteLine("ERROR: failed to InvokeMethodNamed :: " + commandCallParams.Action + " on Object :: " + commandCallParams.Service); + this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.INVALID_ACTION)); + return; + } + }; + + if ((bc is File) || (bc is Accelerometer)) + { + // Due to some issues with the IsolatedStorage in current version of WP8 SDK we have to run all File Api commands synchronously. + // TODO: test this in WP8 RTM + methodInvokation.Invoke(); + } + else + { + new Thread(methodInvokation).Start(); + } + + + } + catch (Exception ex) + { + // ERROR + Debug.WriteLine(String.Format("ERROR: Unable to execute command :: {0}:{1}:{3} ", + commandCallParams.Service, commandCallParams.Action, ex.Message)); + + this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.ERROR)); + return; + } + } + + /// + /// Handles command execution result. + /// + /// Command callback identifier on client side + /// Execution result + private void OnCommandResult(string callbackId, PluginResult result) + { + #region args checking + + if (result == null) + { + Debug.WriteLine("ERROR: OnCommandResult missing result argument"); + return; + } + + if (String.IsNullOrEmpty(callbackId)) + { + Debug.WriteLine("ERROR: OnCommandResult missing callbackId argument"); + return; + } + + if (!String.IsNullOrEmpty(result.CallbackId) && callbackId != result.CallbackId) + { + Debug.WriteLine("Multiple Overlapping Results :: " + result.CallbackId + " :: " + callbackId); + return; + } + + #endregion + + string jsonResult = result.ToJSONString(); + + string callback; + string args = string.Format("('{0}',{1});", callbackId, jsonResult); + + if (result.Result == PluginResult.Status.NO_RESULT || + result.Result == PluginResult.Status.OK) + { + callback = @"(function(callbackId,args) { + try { args.message = JSON.parse(args.message); } catch (ex) { } + cordova.callbackSuccess(callbackId,args); + })" + args; + } + else + { + callback = @"(function(callbackId,args) { + try { args.message = JSON.parse(args.message); } catch (ex) { } + cordova.callbackError(callbackId,args); + })" + args; + } + this.InvokeScriptCallback(new ScriptCallback("eval", new string[] { callback })); + + } + + /// + /// Executes client java script + /// + /// Script to execute on client side + private void InvokeScriptCallback(ScriptCallback script) + { + if (script == null) + { + throw new ArgumentNullException("script"); + } + + if (String.IsNullOrEmpty(script.ScriptName)) + { + throw new ArgumentNullException("ScriptName"); + } + + //Debug.WriteLine("INFO:: About to invoke ::" + script.ScriptName + " with args ::" + script.Args[0]); + this.webBrowser.Dispatcher.BeginInvoke((ThreadStart)delegate() + { + try + { + //Debug.WriteLine("INFO:: InvokingScript::" + script.ScriptName + " with args ::" + script.Args[0]); + this.webBrowser.InvokeScript(script.ScriptName, script.Args); + } + catch (Exception ex) + { + Debug.WriteLine("ERROR: Exception in InvokeScriptCallback :: " + ex.Message); + } + + }); + } + + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/OrientationHelper.cs ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/OrientationHelper.cs b/lib/cordova-wp7/templates/standalone/cordovalib/OrientationHelper.cs new file mode 100644 index 0000000..81a329e --- /dev/null +++ b/lib/cordova-wp7/templates/standalone/cordovalib/OrientationHelper.cs @@ -0,0 +1,128 @@ +/* + 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.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Ink; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using Microsoft.Phone.Controls; + +namespace WPCordovaClassLib.Cordova +{ + public class OrientationHelper + { + protected WebBrowser gapBrowser; + protected PhoneApplicationPage page; + // private PageOrientation CurrentOrientation = PageOrientation.PortraitUp; + //private PageOrientation[] SupportedOrientations; // TODO: + + public OrientationHelper(WebBrowser gapBrowser, PhoneApplicationPage gapPage) + { + this.gapBrowser = gapBrowser; + page = gapPage; + + page.OrientationChanged += new EventHandler(page_OrientationChanged); + gapBrowser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(gapBrowser_LoadCompleted); + + + } + + void gapBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e) + { + int i = 0; + + switch (this.page.Orientation) + { + case PageOrientation.Portrait: // intentional fall through + case PageOrientation.PortraitUp: + i = 0; + break; + case PageOrientation.PortraitDown: + i = 180; + break; + case PageOrientation.Landscape: // intentional fall through + case PageOrientation.LandscapeLeft: + i = -90; + break; + case PageOrientation.LandscapeRight: + i = 90; + break; + } + // Cordova.fireEvent('orientationchange', window); + string jsCallback = String.Format("window.orientation = {0};", i); + + try + { + gapBrowser.InvokeScript("execScript", jsCallback); + } + catch (Exception) + { + } + } + + void page_OrientationChanged(object sender, OrientationChangedEventArgs e) + { + int i = 0; + + switch (e.Orientation) + { + case PageOrientation.Portrait: // intentional fall through + case PageOrientation.PortraitUp: + i = 0; + break; + case PageOrientation.PortraitDown: + i = 180; + break; + case PageOrientation.Landscape: // intentional fall through + case PageOrientation.LandscapeLeft: + i = -90; + break; + case PageOrientation.LandscapeRight: + i = 90; + break; + } + // Cordova.fireEvent('orientationchange', window); + string jsCallback = String.Format("window.orientation = {0};", i); + + try + { + + gapBrowser.InvokeScript("execScript", jsCallback); + + jsCallback = "var evt = document.createEvent('HTMLEvents');"; + jsCallback += "evt.initEvent( 'orientationchange', true, false );"; + jsCallback += "window.dispatchEvent(evt);"; + jsCallback += "if(window.onorientationchange){window.onorientationchange(evt);}"; + + gapBrowser.InvokeScript("execScript", jsCallback); + } + catch (Exception) + { + } + } + + public void HandleCommand(string commandStr) + { + + } + } + + +} http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/PluginResult.cs ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/PluginResult.cs b/lib/cordova-wp7/templates/standalone/cordovalib/PluginResult.cs new file mode 100644 index 0000000..00017d2 --- /dev/null +++ b/lib/cordova-wp7/templates/standalone/cordovalib/PluginResult.cs @@ -0,0 +1,139 @@ +/* + 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.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Ink; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using System.Text; +using System.Diagnostics; + +namespace WPCordovaClassLib.Cordova +{ + /// + /// Represents command execution result + /// + public class PluginResult : EventArgs + { + /// + /// Predefined resultant messages + /// + public static string[] StatusMessages = new string[] + { + "No result", + "OK", + "Class not found", + "Illegal access", + "Instantiation error", + "Malformed url", + "IO error", + "Invalid action", + "JSON error", + "Error" + }; + + /// + /// Possible command results status codes + /// + public enum Status : int + { + NO_RESULT = 0, + OK, + CLASS_NOT_FOUND_EXCEPTION, + ILLEGAL_ACCESS_EXCEPTION, + INSTANTIATION_EXCEPTION, + MALFORMED_URL_EXCEPTION, + IO_EXCEPTION, + INVALID_ACTION, + JSON_EXCEPTION, + ERROR + }; + + public Status Result { get; private set; } + public string Message { get; set; } + public bool KeepCallback { get; set; } + public string CallbackId { get; set; } + + /// + /// Whether command succeded or not + /// + public bool IsSuccess + { + get + { + return this.Result == Status.OK || this.Result == Status.NO_RESULT; + } + } + + /// + /// Creates new instance of the PluginResult class. + /// + /// Execution result + public PluginResult(Status status) + : this(status, PluginResult.StatusMessages[(int)status]) + { + } + + /// + /// Creates new instance of the PluginResult class. + /// + /// Execution result + /// The message + public PluginResult(Status status, object message) + { + this.Result = status; + this.Message = JSON.JsonHelper.Serialize(message); + } + + public string ToJSONString() + { + string res = String.Format("\"status\":{0},\"message\":{1},\"keepCallback\":{2}", + (int)this.Result, + this.Message, + this.KeepCallback.ToString().ToLower()); + + res = "{" + res + "}"; + return res; + + } + + [Obsolete] + public string ToCallbackString(string callbackId, string successCallback, string errorCallback) + { + if (this.IsSuccess) + { + StringBuilder buf = new StringBuilder(""); + buf.Append(String.Format("{0}('{1}',{2});", successCallback, callbackId, this.ToJSONString())); + return buf.ToString(); + } + else + { + return String.Format("{0}('{1}',{2});", errorCallback, callbackId, this.ToJSONString()); + } + } + + public override String ToString() + { + return this.ToJSONString(); + } + + } + +} http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/ScriptCallback.cs ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/ScriptCallback.cs b/lib/cordova-wp7/templates/standalone/cordovalib/ScriptCallback.cs new file mode 100644 index 0000000..7878134 --- /dev/null +++ b/lib/cordova-wp7/templates/standalone/cordovalib/ScriptCallback.cs @@ -0,0 +1,80 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Ink; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using WPCordovaClassLib.Cordova.JSON; +using System.Diagnostics; + +namespace WPCordovaClassLib.Cordova +{ + /// + /// Represents client script function to execute + /// + public class ScriptCallback : EventArgs + { + /// + /// The scripting function to execute. + /// + public string ScriptName { get; private set; } + + /// + /// A variable number of strings to pass to the function as parameters. + /// + public string[] Args { get; private set; } + + /// + /// Creates new instance of a ScriptCallback class. + /// + /// The scripting function to execute + /// A variable number of strings to pass to the function as parameters + public ScriptCallback(string function, string[] args) + { + this.ScriptName = function; + this.Args = args; + } + + /// + /// Creates new instance of a ScriptCallback class. + /// + /// The scripting function to execute + /// The id argument + /// The message argument + /// The value argument + public ScriptCallback(string function, string id, object msg, object value) + { + this.ScriptName = function; + + String arg = String.Format("{{\"id\": {0}, \"msg\": {1}, \"value\": {2}}}", + JsonHelper.Serialize(id), JsonHelper.Serialize(msg), JsonHelper.Serialize(value)); + + this.Args = new string[] { arg }; + } + + + } +} http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/resources/notification-beep.wav ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/resources/notification-beep.wav b/lib/cordova-wp7/templates/standalone/cordovalib/resources/notification-beep.wav new file mode 100644 index 0000000..d0ad085 Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/cordovalib/resources/notification-beep.wav differ http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/resources/notification-beep.wav ---------------------------------------------------------------------- diff --git a/lib/cordova-wp7/templates/standalone/resources/notification-beep.wav b/lib/cordova-wp7/templates/standalone/resources/notification-beep.wav new file mode 100644 index 0000000..d0ad085 Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/resources/notification-beep.wav differ