PageRenderTime 41ms CodeModel.GetById 11ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/windows-phone/wp7/template/cordovalib/CordovaView.xaml.cs

https://github.com/bramhe/phonegap
C# | 517 lines | 375 code | 84 blank | 58 comment | 37 complexity | b5ba6d7acd75fb0f398dc3a93bbb3848 MD5 | raw file
  1/*
  2	Licensed under the Apache License, Version 2.0 (the "License");
  3	you may not use this file except in compliance with the License.
  4	You may obtain a copy of the License at
  5
  6	http://www.apache.org/licenses/LICENSE-2.0
  7
  8	Unless required by applicable law or agreed to in writing, software
  9	distributed under the License is distributed on an "AS IS" BASIS,
 10	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11	See the License for the specific language governing permissions and
 12	limitations under the License.
 13*/
 14
 15using System;
 16using System.Collections.Generic;
 17using System.Linq;
 18using System.Net;
 19using System.Windows;
 20using System.Windows.Controls;
 21using System.Windows.Documents;
 22using System.Windows.Input;
 23using System.Windows.Media;
 24using System.Windows.Media.Animation;
 25using System.Windows.Shapes;
 26using Microsoft.Phone.Controls;
 27using System.IO.IsolatedStorage;
 28using System.Windows.Resources;
 29using System.Windows.Interop;
 30using System.Runtime.Serialization.Json;
 31using System.IO;
 32using System.ComponentModel;
 33using System.Xml.Linq;
 34using WPCordovaClassLib.Cordova.Commands;
 35using System.Diagnostics;
 36using System.Text;
 37using WPCordovaClassLib.Cordova;
 38using System.Threading;
 39using Microsoft.Phone.Shell;
 40using WPCordovaClassLib.Cordova.JSON;
 41using WPCordovaClassLib.CordovaLib;
 42
 43
 44
 45namespace WPCordovaClassLib
 46{
 47    public partial class CordovaView : UserControl
 48    {
 49
 50        /// <summary>
 51        /// Indicates whether web control has been loaded and no additional initialization is needed.
 52        /// Prevents data clearing during page transitions.
 53        /// </summary>
 54        private bool IsBrowserInitialized = false;
 55
 56        /// <summary>
 57        /// Set when the user attaches a back button handler inside the WebBrowser
 58        /// </summary>
 59        private bool OverrideBackButton = false;
 60
 61        /// <summary>
 62        /// Sentinel to keep track of page changes as a result of the hardware back button
 63        /// Set to false when the back-button is pressed, which calls js window.history.back()
 64        /// If the page changes as a result of the back button the event is cancelled.
 65        /// </summary>
 66        private bool PageDidChange = false;
 67
 68        private static string AppRoot = "/app/";
 69
 70
 71        /// <summary>
 72        /// Handles native api calls
 73        /// </summary>
 74        private NativeExecution nativeExecution;
 75
 76        protected BrowserMouseHelper bmHelper;
 77
 78        private ConfigHandler configHandler;
 79
 80        private Dictionary<string, IBrowserDecorator> browserDecorators;
 81
 82        public System.Windows.Controls.Grid _LayoutRoot
 83        {
 84            get
 85            {
 86                return ((System.Windows.Controls.Grid)(this.FindName("LayoutRoot")));
 87            }
 88        }
 89
 90        public WebBrowser Browser
 91        {
 92            get
 93            {
 94                return CordovaBrowser;
 95            }
 96        }
 97
 98        /*
 99         * Setting StartPageUri only has an effect if called before the view is loaded.
100         **/
101        protected Uri _startPageUri = null;
102        public Uri StartPageUri
103        {
104            get
105            {
106                if (_startPageUri == null)
107                {
108                    // default
109                    return new Uri(AppRoot + "www/index.html", UriKind.Relative);
110                }
111                else
112                {
113                    return _startPageUri;
114                }
115            }
116            set
117            {
118                if (!this.IsBrowserInitialized)
119                {
120                    _startPageUri = value;
121                }
122            }
123        }
124
125        public CordovaView()
126        {
127
128            InitializeComponent();
129
130            if (DesignerProperties.IsInDesignTool)
131            {
132                return;
133            }
134
135
136            StartupMode mode = PhoneApplicationService.Current.StartupMode;
137
138            if (mode == StartupMode.Launch)
139            {
140                PhoneApplicationService service = PhoneApplicationService.Current;
141                service.Activated += new EventHandler<Microsoft.Phone.Shell.ActivatedEventArgs>(AppActivated);
142                service.Launching += new EventHandler<LaunchingEventArgs>(AppLaunching);
143                service.Deactivated += new EventHandler<DeactivatedEventArgs>(AppDeactivated);
144                service.Closing += new EventHandler<ClosingEventArgs>(AppClosing);
145            }
146            else
147            {
148
149            }
150
151            configHandler = new ConfigHandler();
152            configHandler.LoadAppPackageConfig();
153
154            if (configHandler.ContentSrc != null)
155            {
156                if (Uri.IsWellFormedUriString(configHandler.ContentSrc, UriKind.Absolute))
157                {
158                    this.StartPageUri = new Uri(configHandler.ContentSrc, UriKind.Absolute);
159                }
160                else
161                {
162                    this.StartPageUri = new Uri(AppRoot + "www/" + configHandler.ContentSrc, UriKind.Relative);
163                }
164            }
165
166
167            browserDecorators = new Dictionary<string, IBrowserDecorator>();
168
169            // initializes native execution logic
170            nativeExecution = new NativeExecution(ref this.CordovaBrowser);
171            bmHelper = new BrowserMouseHelper(ref this.CordovaBrowser);
172
173            CreateDecorators();
174        }
175
176        /*
177         *   browserDecorators are a collection of plugin-like classes (IBrowserDecorator) that add some bit of functionality to the browser.
178         *   These are somewhat different than plugins in that they are usually not async and patch a browser feature that we would
179         *   already expect to have.  Essentially these are browser polyfills that are patched from the outside in.
180         * */
181        void CreateDecorators()
182        {
183            XHRHelper xhrProxy = new XHRHelper();
184            xhrProxy.Browser = CordovaBrowser;
185            browserDecorators.Add("XHRLOCAL", xhrProxy);
186
187            OrientationHelper orientHelper = new OrientationHelper();
188            orientHelper.Browser = CordovaBrowser;
189            browserDecorators.Add("Orientation", orientHelper);
190
191            DOMStorageHelper storageHelper = new DOMStorageHelper();
192            storageHelper.Browser = CordovaBrowser;
193            browserDecorators.Add("DOMStorage", storageHelper);
194
195            ConsoleHelper console = new ConsoleHelper();
196            console.Browser = CordovaBrowser;
197            browserDecorators.Add("ConsoleLog", console);
198
199        }
200
201
202
203        void AppClosing(object sender, ClosingEventArgs e)
204        {
205            //Debug.WriteLine("AppClosing");
206        }
207
208        void AppDeactivated(object sender, DeactivatedEventArgs e)
209        {
210            Debug.WriteLine("INFO: AppDeactivated");
211
212            try
213            {
214                CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('pause');" });
215            }
216            catch (Exception)
217            {
218                Debug.WriteLine("ERROR: Pause event error");
219            }
220        }
221
222        void AppLaunching(object sender, LaunchingEventArgs e)
223        {
224            //Debug.WriteLine("INFO: AppLaunching");
225        }
226
227        void AppActivated(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)
228        {
229            Debug.WriteLine("INFO: AppActivated");
230            try
231            {
232                CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('resume');" });
233            }
234            catch (Exception)
235            {
236                Debug.WriteLine("ERROR: Resume event error");
237            }
238        }
239
240        void GapBrowser_Loaded(object sender, RoutedEventArgs e)
241        {
242            if (DesignerProperties.IsInDesignTool)
243            {
244                return;
245            }
246
247            // prevents refreshing web control to initial state during pages transitions
248            if (this.IsBrowserInitialized) return;
249
250            try
251            {
252
253                // Before we possibly clean the ISO-Store, we need to grab our generated UUID, so we can rewrite it after.
254                string deviceUUID = "";
255
256                using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
257                {
258                    try
259                    {
260                        IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("DeviceID.txt", FileMode.Open, FileAccess.Read, appStorage);
261
262                        using (StreamReader reader = new StreamReader(fileStream))
263                        {
264                            deviceUUID = reader.ReadLine();
265                        }
266                    }
267                    catch (Exception /*ex*/)
268                    {
269                        deviceUUID = Guid.NewGuid().ToString();
270                        Debug.WriteLine("Updating IsolatedStorage for APP:DeviceID :: " + deviceUUID);
271                        IsolatedStorageFileStream file = new IsolatedStorageFileStream("DeviceID.txt", FileMode.Create, FileAccess.Write, appStorage);
272                        using (StreamWriter writeFile = new StreamWriter(file))
273                        {
274                            writeFile.WriteLine(deviceUUID);
275                            writeFile.Close();
276                        }
277                    }
278                }
279
280                StreamResourceInfo streamInfo = Application.GetResourceStream(new Uri("CordovaSourceDictionary.xml", UriKind.Relative));
281
282                if (streamInfo != null)
283                {
284                    StreamReader sr = new StreamReader(streamInfo.Stream);
285                    //This will Read Keys Collection for the xml file
286
287                    XDocument document = XDocument.Parse(sr.ReadToEnd());
288
289                    var files = from results in document.Descendants("FilePath")
290                                select new
291                                {
292                                    path = (string)results.Attribute("Value")
293                                };
294                    StreamResourceInfo fileResourceStreamInfo;
295
296                    using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
297                    {
298
299                        foreach (var file in files)
300                        {
301                            fileResourceStreamInfo = Application.GetResourceStream(new Uri(file.path, UriKind.Relative));
302
303                            if (fileResourceStreamInfo != null)
304                            {
305                                using (BinaryReader br = new BinaryReader(fileResourceStreamInfo.Stream))
306                                {
307                                    byte[] data = br.ReadBytes((int)fileResourceStreamInfo.Stream.Length);
308
309                                    string strBaseDir = AppRoot + file.path.Substring(0, file.path.LastIndexOf(System.IO.Path.DirectorySeparatorChar));
310
311                                    if (!appStorage.DirectoryExists(strBaseDir))
312                                    {
313                                        Debug.WriteLine("INFO: Creating Directory :: " + strBaseDir);
314                                        appStorage.CreateDirectory(strBaseDir);
315                                    }
316
317                                    // This will truncate/overwrite an existing file, or
318                                    using (IsolatedStorageFileStream outFile = appStorage.OpenFile(AppRoot + file.path, FileMode.Create))
319                                    {
320                                        Debug.WriteLine("INFO: Writing data for " + AppRoot + file.path + " and length = " + data.Length);
321                                        using (var writer = new BinaryWriter(outFile))
322                                        {
323                                            writer.Write(data);
324                                        }
325                                    }
326                                }
327                            }
328                            else
329                            {
330                                Debug.WriteLine("ERROR: Failed to write file :: " + file.path + " did you forget to add it to the project?");
331                            }
332                        }
333                    }
334                }
335
336                CordovaBrowser.Navigate(StartPageUri);
337                IsBrowserInitialized = true;
338                AttachHardwareButtonHandlers();
339            }
340            catch (Exception ex)
341            {
342                Debug.WriteLine("ERROR: Exception in GapBrowser_Loaded :: {0}", ex.Message);
343            }
344        }
345
346        void AttachHardwareButtonHandlers()
347        {
348            PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
349            if (frame != null)
350            {
351                PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
352
353                if (page != null)
354                {
355                    page.BackKeyPress += new EventHandler<CancelEventArgs>(page_BackKeyPress);
356                }
357            }
358        }
359
360        void page_BackKeyPress(object sender, CancelEventArgs e)
361        {
362
363            if (OverrideBackButton)
364            {
365                try
366                {
367                    CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('backbutton', {}, true);" });
368                    e.Cancel = true;
369                }
370                catch (Exception ex)
371                {
372                    Console.WriteLine("Exception while invoking backbutton into cordova view: " + ex.Message);
373                }
374            }
375            else
376            {
377                try
378                {
379                    PageDidChange = false;
380
381                    Uri uriBefore = this.Browser.Source;
382                    // calling js history.back with result in a page change if history was valid.
383                    CordovaBrowser.InvokeScript("eval", new string[] { "(function(){window.history.back();})()" });
384
385                    Uri uriAfter = this.Browser.Source;
386
387                    e.Cancel = PageDidChange || (uriBefore != uriAfter);
388                }
389                catch (Exception)
390                {
391                    e.Cancel = false; // exit the app ... ?
392                }
393            }
394        }
395
396        void GapBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
397        {
398            string nativeReady = "(function(){ window.setTimeout(function(){cordova.require('cordova/channel').onNativeReady.fire()},0) })();";
399
400            try
401            {
402                CordovaBrowser.InvokeScript("execScript", new string[] { nativeReady });
403            }
404            catch (Exception ex)
405            {
406                Debug.WriteLine("Error calling js to fire nativeReady event. Did you include cordova.js in your html script tag?");
407            }
408
409            if (this.CordovaBrowser.Opacity < 1)
410            {
411                this.CordovaBrowser.Opacity = 1;
412                RotateIn.Begin();
413            }
414        }
415
416
417        void GapBrowser_Navigating(object sender, NavigatingEventArgs e)
418        {
419            if (!configHandler.URLIsAllowed(e.Uri.ToString()))
420            {
421                e.Cancel = true;
422                return;
423            }
424
425            this.PageDidChange = true;
426            // Debug.WriteLine("GapBrowser_Navigating to :: " + e.Uri.ToString());
427            this.nativeExecution.ResetAllCommands();
428
429            // TODO: check whitelist / blacklist
430            // NOTE: Navigation can be cancelled by setting :        e.Cancel = true;
431        }
432
433        /*
434         *  This method does the work of routing commands
435         *  NotifyEventArgs.Value contains a string passed from JS
436         *  If the command already exists in our map, we will just attempt to call the method(action) specified, and pass the args along
437         *  Otherwise, we create a new instance of the command, add it to the map, and call it ...
438         *  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
439         *  it is simply output to the debugger output, and the method returns.
440         *
441         **/
442        void GapBrowser_ScriptNotify(object sender, NotifyEventArgs e)
443        {
444            string commandStr = e.Value;
445            string commandName = commandStr.Split('/').FirstOrDefault();
446
447            if (browserDecorators.ContainsKey(commandName))
448            {
449                browserDecorators[commandName].HandleCommand(commandStr);
450                return;
451            }
452
453            CordovaCommandCall commandCallParams = CordovaCommandCall.Parse(commandStr);
454
455            if (commandCallParams == null)
456            {
457                // ERROR
458                Debug.WriteLine("ScriptNotify :: " + commandStr);
459            }
460            else if (commandCallParams.Service == "CoreEvents")
461            {
462                switch (commandCallParams.Action.ToLower())
463                {
464                    case "overridebackbutton":
465                        string arg0 = JsonHelper.Deserialize<string[]>(commandCallParams.Args)[0];
466                        this.OverrideBackButton = (arg0 != null && arg0.Length > 0 && arg0.ToLower() == "true");
467                        break;
468                }
469            }
470            else
471            {
472                if (configHandler.IsPluginAllowed(commandCallParams.Service))
473                {
474                    nativeExecution.ProcessCommand(commandCallParams);
475                }
476                else
477                {
478                    Debug.WriteLine("Error::Plugin not allowed in config.xml. " + commandCallParams.Service);
479                }
480            }
481        }
482
483        public void LoadPage(string url)
484        {
485            try
486            {
487                Uri newLoc = new Uri(url,UriKind.RelativeOrAbsolute);
488                CordovaBrowser.Navigate(newLoc);
489            }
490            catch(Exception)
491            {
492
493            }
494        }
495
496        private void GapBrowser_Unloaded(object sender, RoutedEventArgs e)
497        {
498
499        }
500
501        private void GapBrowser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
502        {
503            Debug.WriteLine("GapBrowser_NavigationFailed :: " + e.Uri.ToString());
504        }
505
506        private void GapBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
507        {
508            Debug.WriteLine("GapBrowser_Navigated :: " + e.Uri.ToString());
509            foreach (IBrowserDecorator iBD in browserDecorators.Values)
510            {
511                iBD.InjectScript();
512            }
513        }
514
515
516    }
517}