You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by mw...@apache.org on 2013/05/15 22:35:55 UTC

[16/37] Add WP7 and WP8 platform files.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Media.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Media.cs b/lib/cordova-wp8/templates/standalone/Plugins/Media.cs
new file mode 100644
index 0000000..5de4884
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Media.cs
@@ -0,0 +1,547 @@
+/*  
+	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.Runtime.Serialization;
+using System.Windows;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+    /// <summary>
+    /// Provides the ability to record and play back audio files on a device. 
+    /// </summary>
+    public class Media : BaseCommand
+    {
+        /// <summary>
+        /// Audio player objects
+        /// </summary>
+        private static Dictionary<string, AudioPlayer> players = new Dictionary<string, AudioPlayer>();
+
+        /// <summary>
+        /// Represents Media action options.
+        /// </summary>
+        [DataContract]
+        public class MediaOptions
+        {
+            /// <summary>
+            /// Audio id
+            /// </summary>
+            [DataMember(Name = "id", IsRequired = true)]
+            public string Id { get; set; }
+
+            /// <summary>
+            /// Path to audio file
+            /// </summary>
+            [DataMember(Name = "src")]
+            public string Src { get; set; }
+
+            /// <summary>
+            /// New track position
+            /// </summary>
+            [DataMember(Name = "milliseconds")]
+            public int Milliseconds { get; set; }
+        }
+
+        /// <summary>
+        /// Releases the audio player instance to save memory.
+        /// </summary>  
+        public void release(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                if (!Media.players.ContainsKey(mediaOptions.Id))
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.OK, false));
+                    return;
+                }
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        AudioPlayer audio = Media.players[mediaOptions.Id];
+                        Media.players.Remove(mediaOptions.Id);
+                        audio.Dispose();
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK, true));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+        /// <summary>
+        /// Starts recording and save the specified file 
+        /// </summary>
+        public void startRecordingAudio(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                    mediaOptions.Src = optionsString[1];
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                if (mediaOptions != null)
+                {
+
+                    Deployment.Current.Dispatcher.BeginInvoke(() =>
+                    {
+                        try
+                        {
+                            AudioPlayer audio;
+                            if (!Media.players.ContainsKey(mediaOptions.Id))
+                            {
+                                audio = new AudioPlayer(this, mediaOptions.Id);
+                                Media.players.Add(mediaOptions.Id, audio);
+                            }
+                            else
+                            {
+                                audio = Media.players[mediaOptions.Id];
+                            }
+
+                            if (audio != null)
+                            {
+                                audio.startRecording(mediaOptions.Src);
+                                DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                            }
+                            else
+                            {
+                                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error accessing AudioPlayer for key " + mediaOptions.Id));
+                            }
+                            
+                            
+                        }
+                        catch (Exception e)
+                        {
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                        }
+
+                    });
+                }
+                else
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                }
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+        /// <summary>
+        /// Stops recording and save to the file specified when recording started 
+        /// </summary>
+        public void stopRecordingAudio(string options)
+        {
+            try
+            {
+                string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaId))
+                        {
+                            AudioPlayer audio = Media.players[mediaId];
+                            audio.stopRecording();
+                            Media.players.Remove(mediaId);
+                        }
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+            }
+        }
+
+        public void setVolume(string options) // id,volume
+        {
+            try
+            {
+                string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                string id = optionsString[0];
+                double volume = double.Parse(optionsString[1]);
+
+                if (Media.players.ContainsKey(id))
+                {
+                    Deployment.Current.Dispatcher.BeginInvoke(() =>
+                    {
+                        try
+                        {
+                            AudioPlayer player = Media.players[id];
+                            player.setVolume(volume);
+                        }
+                        catch (Exception e)
+                        {
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                        }
+                    });
+                }
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Error parsing options into setVolume method"));
+                return;
+            }
+        }
+
+        // Some Audio Notes:
+        // In the Windows Phone Emulator, playback of video or audio content using the MediaElement control is not supported.
+        // While playing, a MediaElement stops all other media playback on the phone.
+        // Multiple MediaElement controls are NOT supported
+
+        // Called when you create a new Media('blah') object in JS.
+        public void create(string options)
+        {
+            // Debug.WriteLine("Creating Audio :: " + options);
+            try
+            {
+                MediaOptions mediaOptions;
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                    mediaOptions.Src = optionsString[1];
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Error parsing options into create method"));
+                    return;
+                }
+
+                AudioPlayer audio = new AudioPlayer(this, mediaOptions.Id);
+                Media.players.Add(mediaOptions.Id, audio);
+                DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+        /// <summary>
+        /// Starts or resume playing audio file 
+        /// </summary>
+        public void startPlayingAudio(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                    mediaOptions.Src = optionsString[1];
+                    if (optionsString.Length > 2 && optionsString[2] != null)
+                    {
+                        mediaOptions.Milliseconds = int.Parse(optionsString[2]);
+                    }
+
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                AudioPlayer audio;
+
+                if (!Media.players.ContainsKey(mediaOptions.Id))
+                {
+                    audio = new AudioPlayer(this, mediaOptions.Id);
+                    Media.players.Add(mediaOptions.Id, audio);
+                }
+                else
+                {
+                    //Debug.WriteLine("INFO: startPlayingAudio FOUND mediaPlayer for " + mediaOptions.Id);
+                    audio = Media.players[mediaOptions.Id];
+                }
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        audio.startPlaying(mediaOptions.Src);
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+
+        /// <summary>
+        /// Seeks to a location
+        /// </summary>
+        public void seekToAudio(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                    if (optionsString.Length > 1 && optionsString[1] != null)
+                    {
+                        mediaOptions.Milliseconds = int.Parse(optionsString[1]);
+                    }
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaOptions.Id))
+                        {
+                            AudioPlayer audio = Media.players[mediaOptions.Id];
+                            audio.seekToPlaying(mediaOptions.Milliseconds);
+                        }
+                        else
+                        {
+                            Debug.WriteLine("ERROR: seekToAudio could not find mediaPlayer for " + mediaOptions.Id);
+                        }
+
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+        /// <summary>
+        /// Pauses playing 
+        /// </summary>
+        public void pausePlayingAudio(string options)
+        {
+
+            try
+            {
+                string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaId))
+                        {
+                            AudioPlayer audio = Media.players[mediaId];
+                            audio.pausePlaying();
+                        }
+                        else
+                        {
+                            Debug.WriteLine("ERROR: pausePlayingAudio could not find mediaPlayer for " + mediaId);
+                        }
+
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+
+
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+            }
+
+
+        }
+
+
+        /// <summary>
+        /// Stops playing the audio file
+        /// </summary>
+        public void stopPlayingAudio(String options)
+        {
+            try
+            {
+                string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaId))
+                        {
+                            AudioPlayer audio = Media.players[mediaId];
+                            audio.stopPlaying();
+                        }
+                        else
+                        {
+                            Debug.WriteLine("stopPlaying could not find mediaPlayer for " + mediaId);
+                        }
+
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+            }
+        }
+
+        /// <summary>
+        /// Gets current position of playback
+        /// </summary>
+        public void getCurrentPositionAudio(string options)
+        {
+            try
+            {
+                string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaId))
+                        {
+                            AudioPlayer audio = Media.players[mediaId];
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getCurrentPosition()));
+                        }
+                        else
+                        {
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.OK, -1));
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+        }
+
+
+        /// <summary>
+        /// Gets the duration of the audio file
+        /// </summary>
+        
+        [Obsolete("This method will be removed shortly")]
+        public void getDurationAudio(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+
+                try
+                {
+                    mediaOptions = JSON.JsonHelper.Deserialize<MediaOptions>(options);
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                AudioPlayer audio;
+                if (Media.players.ContainsKey(mediaOptions.Id))
+                {
+                    audio = Media.players[mediaOptions.Id];
+                }
+                else
+                {
+                    Debug.WriteLine("ERROR: getDurationAudio could not find mediaPlayer for " + mediaOptions.Id);
+                    audio = new AudioPlayer(this, mediaOptions.Id);
+                    Media.players.Add(mediaOptions.Id, audio);
+                }
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getDuration(mediaOptions.Src)));
+                });
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/MimeTypeMapper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/MimeTypeMapper.cs b/lib/cordova-wp8/templates/standalone/Plugins/MimeTypeMapper.cs
new file mode 100644
index 0000000..a2794f5
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/MimeTypeMapper.cs
@@ -0,0 +1,101 @@
+/*  
+	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.Collections.Generic;
+using System.IO;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+    /// <summary>
+    /// Represents file extension to mime type mapper.
+    /// </summary>
+    public static class MimeTypeMapper
+    {
+        /// <summary>
+        /// For unknown type it is recommended to use 'application/octet-stream'
+        /// http://stackoverflow.com/questions/1176022/unknown-file-type-mime
+        /// </summary>
+        private static string DefaultMimeType = "application/octet-stream";
+
+        /// <summary>
+        /// Stores mime type for all necessary extension
+        /// </summary>
+        private static readonly Dictionary<string, string> MIMETypesDictionary = new Dictionary<string, string>
+                                                                             {                                                                                
+                                                                                 {"avi", "video/x-msvideo"},
+                                                                                 {"bmp", "image/bmp"},                                                                                                                                                                
+                                                                                 {"gif", "image/gif"},
+                                                                                 {"html","text/html"},                                                                              
+                                                                                 {"jpe", "image/jpeg"},
+                                                                                 {"jpeg", "image/jpeg"},
+                                                                                 {"jpg", "image/jpeg"},     
+                                                                                 {"js","text/javascript"},                                                                         
+                                                                                 {"mov", "video/quicktime"},
+                                                                                 {"mp2", "audio/mpeg"},
+                                                                                 {"mp3", "audio/mpeg"},
+                                                                                 {"mp4", "video/mp4"},
+                                                                                 {"mpe", "video/mpeg"},
+                                                                                 {"mpeg", "video/mpeg"},
+                                                                                 {"mpg", "video/mpeg"},
+                                                                                 {"mpga", "audio/mpeg"},                                                                                
+                                                                                 {"pbm", "image/x-portable-bitmap"},
+                                                                                 {"pcm", "audio/x-pcm"},
+                                                                                 {"pct", "image/pict"},
+                                                                                 {"pgm", "image/x-portable-graymap"},
+                                                                                 {"pic", "image/pict"},
+                                                                                 {"pict", "image/pict"},
+                                                                                 {"png", "image/png"},
+                                                                                 {"pnm", "image/x-portable-anymap"},
+                                                                                 {"pnt", "image/x-macpaint"},
+                                                                                 {"pntg", "image/x-macpaint"},
+                                                                                 {"ppm", "image/x-portable-pixmap"},
+                                                                                 {"qt", "video/quicktime"},
+                                                                                 {"ra", "audio/x-pn-realaudio"},
+                                                                                 {"ram", "audio/x-pn-realaudio"},
+                                                                                 {"ras", "image/x-cmu-raster"},
+                                                                                 {"rgb", "image/x-rgb"},
+                                                                                 {"snd", "audio/basic"},
+                                                                                 {"txt", "text/plain"},
+                                                                                 {"tif", "image/tiff"},
+                                                                                 {"tiff", "image/tiff"},
+                                                                                 {"wav", "audio/x-wav"},
+                                                                                 {"wbmp", "image/vnd.wap.wbmp"},
+
+                                                                             };
+        /// <summary>
+        /// Gets mime type by file extension
+        /// </summary>
+        /// <param name="fileName">file name to extract extension</param>
+        /// <returns>mime type</returns>
+        public static string GetMimeType(string fileName)
+        {
+            string ext = Path.GetExtension(fileName);
+
+            // invalid extension
+            if (string.IsNullOrEmpty(ext) || !ext.StartsWith("."))
+            {
+                return DefaultMimeType;
+            }
+
+            ext = ext.Remove(0, 1);
+
+            if (MIMETypesDictionary.ContainsKey(ext))
+            {
+                return MIMETypesDictionary[ext];
+            }
+
+            return DefaultMimeType;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/NetworkStatus.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/NetworkStatus.cs b/lib/cordova-wp8/templates/standalone/Plugins/NetworkStatus.cs
new file mode 100644
index 0000000..12eb061
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/NetworkStatus.cs
@@ -0,0 +1,129 @@
+/*  
+	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.Net;
+using System.Net.NetworkInformation;
+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.Net.NetworkInformation;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+
+    // http://msdn.microsoft.com/en-us/library/microsoft.phone.net.networkinformation(v=VS.92).aspx
+    // http://msdn.microsoft.com/en-us/library/microsoft.phone.net.networkinformation.devicenetworkinformation(v=VS.92).aspx
+
+    public class NetworkStatus : BaseCommand
+    {
+        const string UNKNOWN = "unknown";
+        const string ETHERNET = "ethernet";
+        const string WIFI = "wifi";
+        const string CELL_2G = "2g";
+        const string CELL_3G = "3g";
+        const string CELL_4G = "4g";
+        const string NONE = "none";
+        const string CELL = "cellular";
+
+        private bool HasCallback = false;
+
+        public NetworkStatus()
+        {
+            DeviceNetworkInformation.NetworkAvailabilityChanged += new EventHandler<NetworkNotificationEventArgs>(ChangeDetected);
+        }
+
+        public override void OnResume(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)
+        {
+            this.getConnectionInfo("");
+        }
+
+        public void getConnectionInfo(string empty)
+        {
+            HasCallback = true;
+            updateConnectionType(checkConnectionType());
+        }
+
+        private string checkConnectionType()
+        {
+            if (DeviceNetworkInformation.IsNetworkAvailable)
+            {
+                if (DeviceNetworkInformation.IsWiFiEnabled)
+                {
+                    return WIFI;
+                }
+                else
+                {
+                    return DeviceNetworkInformation.IsCellularDataEnabled ? CELL : UNKNOWN;
+                }
+            }
+            return NONE;
+        }
+
+        private string checkConnectionType(NetworkInterfaceSubType type)
+        {
+            switch (type)
+            {
+                case NetworkInterfaceSubType.Cellular_1XRTT: //cell
+                case NetworkInterfaceSubType.Cellular_GPRS: //cell
+                    return CELL;
+                case NetworkInterfaceSubType.Cellular_EDGE: //2
+                    return CELL_2G;
+                case NetworkInterfaceSubType.Cellular_3G:
+                case NetworkInterfaceSubType.Cellular_EVDO: //3
+                case NetworkInterfaceSubType.Cellular_EVDV: //3 
+                case NetworkInterfaceSubType.Cellular_HSPA: //3
+                    return CELL_3G;
+                case NetworkInterfaceSubType.WiFi:
+                    return WIFI;
+                case NetworkInterfaceSubType.Unknown:
+                case NetworkInterfaceSubType.Desktop_PassThru:
+                default:
+                    return UNKNOWN;
+            }
+        }
+
+        void ChangeDetected(object sender, NetworkNotificationEventArgs e)
+        {
+            switch (e.NotificationType)
+            {
+                case NetworkNotificationType.InterfaceConnected:
+                    updateConnectionType(checkConnectionType(e.NetworkInterface.InterfaceSubtype));
+                    break;
+                case NetworkNotificationType.InterfaceDisconnected:
+                    updateConnectionType(NONE);
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        private void updateConnectionType(string type)
+        {
+            // This should also implicitly fire offline/online events as that is handled on the JS side
+            if (this.HasCallback)
+            {
+                PluginResult result = new PluginResult(PluginResult.Status.OK, type);
+                result.KeepCallback = true;
+                DispatchCommandResult(result);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Notification.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Notification.cs b/lib/cordova-wp8/templates/standalone/Plugins/Notification.cs
new file mode 100644
index 0000000..0759c72
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Notification.cs
@@ -0,0 +1,361 @@
+/*  
+	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.Windows;
+using System.Windows.Controls;
+using Microsoft.Devices;
+using System.Runtime.Serialization;
+using System.Threading;
+using System.Windows.Resources;
+using Microsoft.Phone.Controls;
+using Microsoft.Xna.Framework.Audio;
+using WPCordovaClassLib.Cordova.UI;
+using System.Diagnostics;
+
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+    public class Notification : BaseCommand
+    {
+        static ProgressBar progressBar = null;
+        const int DEFAULT_DURATION = 5;
+
+        private NotificationBox notifyBox;
+
+        private PhoneApplicationPage Page
+        {
+            get
+            {
+                PhoneApplicationPage page = null;
+                PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+                if (frame != null)
+                {
+                    page = frame.Content as PhoneApplicationPage;
+                }
+                return page;
+            }
+        }
+
+        // blink api - doesn't look like there is an equivalent api we can use...
+
+        [DataContract]
+        public class AlertOptions
+        {
+            [OnDeserializing]
+            public void OnDeserializing(StreamingContext context)
+            {
+                // set defaults
+                this.message = "message";
+                this.title = "Alert";
+                this.buttonLabel = "ok";
+            }
+
+            /// <summary>
+            /// message to display in the alert box
+            /// </summary>
+            [DataMember]
+            public string message;
+
+            /// <summary>
+            /// title displayed on the alert window
+            /// </summary>
+            [DataMember]
+            public string title;
+
+            /// <summary>
+            /// text to display on the button
+            /// </summary>
+            [DataMember]
+            public string buttonLabel;
+        }
+
+        public void alert(string options)
+        {
+            string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+            AlertOptions alertOpts = new AlertOptions();
+            alertOpts.message = args[0];
+            alertOpts.title = args[1];
+            alertOpts.buttonLabel = args[2];
+            string aliasCurrentCommandCallbackId = args[3];
+
+            Deployment.Current.Dispatcher.BeginInvoke(() =>
+            {
+                PhoneApplicationPage page = Page;
+                if (page != null)
+                {
+                    Grid grid = page.FindName("LayoutRoot") as Grid;
+                    if (grid != null)
+                    {
+                        var previous = notifyBox;
+                        notifyBox = new NotificationBox();
+                        notifyBox.Tag = new { previous = previous, callbackId = aliasCurrentCommandCallbackId };
+                        notifyBox.PageTitle.Text = alertOpts.title;
+                        notifyBox.SubTitle.Text = alertOpts.message;
+                        Button btnOK = new Button();
+                        btnOK.Content = alertOpts.buttonLabel;
+                        btnOK.Click += new RoutedEventHandler(btnOK_Click);
+                        btnOK.Tag = 1;
+                        notifyBox.ButtonPanel.Children.Add(btnOK);
+                        grid.Children.Add(notifyBox);
+
+                        if (previous == null)
+                        {
+                            page.BackKeyPress += page_BackKeyPress;
+                        }
+                    }
+                }
+                else
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION));
+                }
+            });
+        }
+
+        public void confirm(string options)
+        {
+            string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+            AlertOptions alertOpts = new AlertOptions();
+            alertOpts.message = args[0];
+            alertOpts.title = args[1];
+            alertOpts.buttonLabel = args[2];
+            string aliasCurrentCommandCallbackId = args[3];
+
+            Deployment.Current.Dispatcher.BeginInvoke(() =>
+            {
+                PhoneApplicationPage page = Page;
+                if (page != null)
+                {
+                    Grid grid = page.FindName("LayoutRoot") as Grid;
+                    if (grid != null)
+                    {
+                        var previous = notifyBox;
+                        notifyBox = new NotificationBox();
+                        notifyBox.Tag = new { previous = previous, callbackId = aliasCurrentCommandCallbackId };
+                        notifyBox.PageTitle.Text = alertOpts.title;
+                        notifyBox.SubTitle.Text = alertOpts.message;
+
+                        string[] labels = JSON.JsonHelper.Deserialize<string[]>(alertOpts.buttonLabel);
+
+                        if (labels == null)
+                        {
+                            labels = alertOpts.buttonLabel.Split(',');
+                        }
+
+                        for (int n = 0; n < labels.Length; n++)
+                        {
+                            Button btn = new Button();
+                            btn.Content = labels[n];
+                            btn.Tag = n;
+                            btn.Click += new RoutedEventHandler(btnOK_Click);
+                            notifyBox.ButtonPanel.Children.Add(btn);
+                        }
+
+                        grid.Children.Add(notifyBox);
+                        if (previous == null)
+                        {
+                            page.BackKeyPress += page_BackKeyPress;
+                        }
+                    }
+                }
+                else
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION));
+                }
+            });
+        }
+
+        void page_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
+        {
+            PhoneApplicationPage page = sender as PhoneApplicationPage;
+            string callbackId = "";
+            if (page != null && notifyBox != null)
+            {
+                Grid grid = page.FindName("LayoutRoot") as Grid;
+                if (grid != null)
+                {
+                    grid.Children.Remove(notifyBox);
+                    dynamic notifBoxData = notifyBox.Tag;
+                    notifyBox = notifBoxData.previous as NotificationBox;
+                    callbackId = notifBoxData.callbackId as string;
+                }
+                if (notifyBox == null)
+                {
+                    page.BackKeyPress -= page_BackKeyPress;
+                }
+                e.Cancel = true;
+            }
+
+            DispatchCommandResult(new PluginResult(PluginResult.Status.OK, 0), callbackId);
+        }
+
+        void btnOK_Click(object sender, RoutedEventArgs e)
+        {
+            Button btn = sender as Button;
+            FrameworkElement notifBoxParent = null;
+            int retVal = 0;
+            string callbackId = "";
+            if (btn != null)
+            {
+                retVal = (int)btn.Tag + 1;
+
+                notifBoxParent = btn.Parent as FrameworkElement;
+                while ((notifBoxParent = notifBoxParent.Parent as FrameworkElement) != null &&
+                       !(notifBoxParent is NotificationBox)) ;
+            }
+            if (notifBoxParent != null)
+            {
+                PhoneApplicationPage page = Page;
+                if (page != null)
+                {
+                    Grid grid = page.FindName("LayoutRoot") as Grid;
+                    if (grid != null)
+                    {
+                        grid.Children.Remove(notifBoxParent);
+                    }
+                    
+                    dynamic notifBoxData = notifBoxParent.Tag;
+                    notifyBox = notifBoxData.previous as NotificationBox;
+                    callbackId = notifBoxData.callbackId as string;
+
+                    if (notifyBox == null)
+                    {
+                        page.BackKeyPress -= page_BackKeyPress;
+                    }
+                }
+
+            }
+            DispatchCommandResult(new PluginResult(PluginResult.Status.OK, retVal),callbackId);
+        }
+
+
+
+        public void beep(string options)
+        {
+            string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+            int times = int.Parse(args[0]);
+
+            string resourcePath = BaseCommand.GetBaseURL() + "resources/notification-beep.wav";
+
+            StreamResourceInfo sri = Application.GetResourceStream(new Uri(resourcePath, UriKind.Relative));
+
+            if (sri != null)
+            {
+                SoundEffect effect = SoundEffect.FromStream(sri.Stream);
+                SoundEffectInstance inst = effect.CreateInstance();
+                ThreadPool.QueueUserWorkItem((o) =>
+                {
+                    // cannot interact with UI !!
+                    do
+                    {
+                        inst.Play();
+                        Thread.Sleep(effect.Duration + TimeSpan.FromMilliseconds(100));
+                    }
+                    while (--times > 0);
+
+                });
+
+            }
+
+            // TODO: may need a listener to trigger DispatchCommandResult after the alarm has finished executing...
+            DispatchCommandResult();
+        }
+
+        // Display an indeterminate progress indicator
+        public void activityStart(string unused)
+        {
+
+            Deployment.Current.Dispatcher.BeginInvoke(() =>
+            {
+                PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+
+                if (frame != null)
+                {
+                    PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+
+                    if (page != null)
+                    {
+                        var temp = page.FindName("LayoutRoot");
+                        Grid grid = temp as Grid;
+                        if (grid != null)
+                        {
+                            if (progressBar != null)
+                            {
+                                grid.Children.Remove(progressBar);
+                            }
+                            progressBar = new ProgressBar();
+                            progressBar.IsIndeterminate = true;
+                            progressBar.IsEnabled = true;
+
+                            grid.Children.Add(progressBar);
+                        }
+                    }
+                }
+            });
+        }
+
+
+        // Remove our indeterminate progress indicator
+        public void activityStop(string unused)
+        {
+            Deployment.Current.Dispatcher.BeginInvoke(() =>
+            {
+                if (progressBar != null)
+                {
+                    progressBar.IsEnabled = false;
+                    PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+                    if (frame != null)
+                    {
+                        PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+                        if (page != null)
+                        {
+                            Grid grid = page.FindName("LayoutRoot") as Grid;
+                            if (grid != null)
+                            {
+                                grid.Children.Remove(progressBar);
+                            }
+                        }
+                    }
+                    progressBar = null;
+                }
+            });
+        }
+
+        public void vibrate(string vibrateDuration)
+        {
+
+            int msecs = 200; // set default
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(vibrateDuration);
+
+                msecs = int.Parse(args[0]);
+                if (msecs < 1)
+                {
+                    msecs = 1;
+                }
+            }
+            catch (FormatException)
+            {
+
+            }
+
+            VibrateController.Default.Start(TimeSpan.FromMilliseconds(msecs));
+
+            // TODO: may need to add listener to trigger DispatchCommandResult when the vibration ends...
+            DispatchCommandResult();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioCaptureTask.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioCaptureTask.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioCaptureTask.cs
new file mode 100644
index 0000000..3d7d60f
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioCaptureTask.cs
@@ -0,0 +1,107 @@
+/*  
+	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.IO;
+using System.Windows;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+    /// <summary>
+    /// Allows an application to launch the Audio Recording application. 
+    /// Use this to allow users to record audio from your application.
+    /// </summary>
+    public class AudioCaptureTask
+    {
+        /// <summary>
+        /// Represents recorded audio returned from a call to the Show method of
+        /// a WPCordovaClassLib.Cordova.Controls.AudioCaptureTask object
+        /// </summary>
+        public class AudioResult : TaskEventArgs
+        {
+            /// <summary>
+            /// Initializes a new instance of the AudioResult class.
+            /// </summary>
+            public AudioResult()
+            { }
+
+            /// <summary>
+            /// Initializes a new instance of the AudioResult class
+            /// with the specified Microsoft.Phone.Tasks.TaskResult.
+            /// </summary>
+            /// <param name="taskResult">Associated Microsoft.Phone.Tasks.TaskResult</param>
+            public AudioResult(TaskResult taskResult)
+                : base(taskResult)
+            { }
+
+            /// <summary>
+            ///  Gets the file name of the recorded audio.
+            /// </summary>
+            public Stream AudioFile { get; internal set; }
+
+            /// <summary>
+            /// Gets the stream containing the data for the recorded audio.
+            /// </summary>
+            public string AudioFileName { get; internal set; }
+        }
+
+        /// <summary>
+        /// Occurs when a audio recording task is completed.
+        /// </summary>
+        public event EventHandler<AudioResult> Completed;
+
+        /// <summary>
+        /// Shows Audio Recording application
+        /// </summary>
+        public void Show()
+        {
+            Deployment.Current.Dispatcher.BeginInvoke(() =>
+            {
+                var root = Application.Current.RootVisual as PhoneApplicationFrame;
+
+                root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(NavigationService_Navigated);
+
+                string baseUrl = WPCordovaClassLib.Cordova.Commands.BaseCommand.GetBaseURL();
+                // dummy parameter is used to always open a fresh version
+                root.Navigate(new System.Uri( baseUrl + "CordovaLib/UI/AudioRecorder.xaml?dummy=" + Guid.NewGuid().ToString(), UriKind.Relative));
+
+            });
+        }
+
+        /// <summary>
+        /// Performs additional configuration of the recording application.
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void NavigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            if (!(e.Content is AudioRecorder)) return;
+
+            (Application.Current.RootVisual as PhoneApplicationFrame).Navigated -= NavigationService_Navigated;
+
+            AudioRecorder audioRecorder = (AudioRecorder)e.Content;
+
+            if (audioRecorder != null)
+            {
+                audioRecorder.Completed += this.Completed;
+            }
+            else if (this.Completed != null)
+            {
+                this.Completed(this, new AudioResult(TaskResult.Cancel));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml
new file mode 100644
index 0000000..0fd26ab
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml
@@ -0,0 +1,66 @@
+<!--
+ 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. 
+-->
+<phone:PhoneApplicationPage 
+    x:Class="WPCordovaClassLib.Cordova.UI.AudioRecorder"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    FontFamily="{StaticResource PhoneFontFamilyNormal}"
+    FontSize="{StaticResource PhoneFontSizeNormal}"
+    Foreground="{StaticResource PhoneForegroundBrush}"
+    SupportedOrientations="Portrait" Orientation="Portrait"
+    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
+    shell:SystemTray.IsVisible="True">
+
+    <!--LayoutRoot is the root grid where all page content is placed-->
+    <Grid x:Name="LayoutRoot" Background="Transparent">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto"/>
+            <RowDefinition Height="*"/>
+        </Grid.RowDefinitions>
+
+        <!--TitlePanel contains the name of the application and page title-->
+        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="0,17,0,28">
+            <TextBlock x:Name="PageTitle" Text="Audio recorder" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
+        </StackPanel>
+
+        <!--ContentPanel - place additional content here-->
+        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
+            <Button Name="btnStartStop" Content="Start" Height="72" HorizontalAlignment="Left" Margin="156,96,0,0"  VerticalAlignment="Top" Width="160" Click="btnStartStop_Click" />
+            <Button Name="btnTake" Content="Take" IsEnabled="False" Height="72" HorizontalAlignment="Left" Margin="155,182,0,0" VerticalAlignment="Top" Width="160" Click="btnTake_Click" />
+            <TextBlock Height="30" HorizontalAlignment="Left" Margin="168,60,0,0" Name="txtDuration" Text="Duration: 00:00" VerticalAlignment="Top" />
+        </Grid>
+    </Grid>
+ 
+    <!--Sample code showing usage of ApplicationBar-->
+    <!--<phone:PhoneApplicationPage.ApplicationBar>
+        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
+            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
+            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
+            <shell:ApplicationBar.MenuItems>
+                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
+                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
+            </shell:ApplicationBar.MenuItems>
+        </shell:ApplicationBar>
+    </phone:PhoneApplicationPage.ApplicationBar>-->
+
+</phone:PhoneApplicationPage>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs
new file mode 100644
index 0000000..01a0832
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs
@@ -0,0 +1,307 @@
+/*  
+	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 Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using System;
+using System.IO;
+using System.IO.IsolatedStorage;
+using System.Windows;
+using System.Windows.Threading;
+using WPCordovaClassLib.Cordova.Commands;
+using AudioResult = WPCordovaClassLib.Cordova.UI.AudioCaptureTask.AudioResult;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+    /// <summary>
+    /// Implements Audio Recording application
+    /// </summary>
+    public partial class AudioRecorder : PhoneApplicationPage
+    {
+
+        #region Constants
+
+        private const string RecordingStartCaption = "Start";
+        private const string RecordingStopCaption = "Stop";
+
+        private const string LocalFolderName = "AudioCache";
+        private const string FileNameFormat = "Audio-{0}.wav";
+
+        #endregion
+
+        #region Callbacks
+
+        /// <summary>
+        /// Occurs when a audio recording task is completed.
+        /// </summary>
+        public event EventHandler<AudioResult> Completed;
+
+        #endregion
+
+        #region Fields
+
+        /// <summary>
+        /// Audio source
+        /// </summary>
+        private Microphone microphone;
+
+        /// <summary>
+        /// Temporary buffer to store audio chunk
+        /// </summary>
+        private byte[] buffer;
+
+        /// <summary>
+        /// Recording duration
+        /// </summary>
+        private TimeSpan duration;
+
+        /// <summary>
+        /// Output buffer
+        /// </summary>
+        private MemoryStream memoryStream;
+
+        /// <summary>
+        /// Xna game loop dispatcher
+        /// </summary>
+        DispatcherTimer dtXna;
+
+        /// <summary>
+        /// Recording result, dispatched back when recording page is closed
+        /// </summary>
+        private AudioResult result = new AudioResult(TaskResult.Cancel);
+
+        /// <summary>
+        /// Whether we are recording audio now
+        /// </summary>
+        private bool IsRecording
+        {
+            get
+            {
+                return (this.microphone != null && this.microphone.State == MicrophoneState.Started);
+            }
+        }
+
+        #endregion
+
+        /// <summary>
+        /// Creates new instance of the AudioRecorder class.
+        /// </summary>
+        public AudioRecorder()
+        {
+
+            this.InitializeXnaGameLoop();
+
+            // microphone requires special XNA initialization to work
+            InitializeComponent();
+        }
+
+        /// <summary>
+        /// Starts recording, data is stored in memory
+        /// </summary>
+        private void StartRecording()
+        {
+            this.microphone = Microphone.Default;
+            this.microphone.BufferDuration = TimeSpan.FromMilliseconds(500);
+
+            this.btnTake.IsEnabled = false;
+            this.btnStartStop.Content = RecordingStopCaption;
+
+            this.buffer = new byte[microphone.GetSampleSizeInBytes(this.microphone.BufferDuration)];
+            this.microphone.BufferReady += new EventHandler<EventArgs>(MicrophoneBufferReady);
+
+            this.memoryStream = new MemoryStream();
+            this.memoryStream.InitializeWavStream(this.microphone.SampleRate);
+
+            this.duration = new TimeSpan(0);
+
+            this.microphone.Start();
+        }
+
+        /// <summary>
+        /// Stops recording
+        /// </summary>
+        private void StopRecording()
+        {
+            this.microphone.Stop();
+
+            this.microphone.BufferReady -= MicrophoneBufferReady;
+
+            this.microphone = null;
+
+            btnStartStop.Content = RecordingStartCaption;
+
+            // check there is some data
+            this.btnTake.IsEnabled = true;
+        }
+
+        /// <summary>
+        /// Handles Start/Stop events
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void btnStartStop_Click(object sender, RoutedEventArgs e)
+        {
+
+            if (this.IsRecording)
+            {
+                this.StopRecording();
+            }
+            else
+            {
+                this.StartRecording();
+            }
+        }
+
+        /// <summary>
+        /// Handles Take button click
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void btnTake_Click(object sender, RoutedEventArgs e)
+        {
+            this.result = this.SaveAudioClipToLocalStorage();
+
+            if (Completed != null)
+            {
+                Completed(this, result);
+            }
+
+            if (this.NavigationService.CanGoBack)
+            {
+                this.NavigationService.GoBack();
+            }
+        }
+
+        /// <summary>
+        /// Handles page closing event, stops recording if needed and dispatches results.
+        /// </summary>
+        /// <param name="e"></param>
+        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
+        {
+            if (IsRecording)
+            {
+                StopRecording();
+            }
+
+            this.FinalizeXnaGameLoop();
+
+            base.OnNavigatedFrom(e);
+        }
+
+        /// <summary>
+        /// Copies data from microphone to memory storages and updates recording state
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void MicrophoneBufferReady(object sender, EventArgs e)
+        {
+            this.microphone.GetData(this.buffer);
+            this.memoryStream.Write(this.buffer, 0, this.buffer.Length);
+            TimeSpan bufferDuration = this.microphone.BufferDuration;
+
+            this.Dispatcher.BeginInvoke(() =>
+            {
+                this.duration += bufferDuration;
+
+                this.txtDuration.Text = "Duration: " +
+                    this.duration.Minutes.ToString().PadLeft(2, '0') + ":" +
+                    this.duration.Seconds.ToString().PadLeft(2, '0');
+            });
+
+        }
+
+        /// <summary>
+        /// Writes audio data from memory to isolated storage
+        /// </summary>
+        /// <returns></returns>
+        private AudioResult SaveAudioClipToLocalStorage()
+        {
+            if (this.memoryStream == null || this.memoryStream.Length <= 0)
+            {
+                return new AudioResult(TaskResult.Cancel);
+            }
+
+            this.memoryStream.UpdateWavStream();
+
+            // save audio data to local isolated storage
+
+            string filename = String.Format(FileNameFormat, Guid.NewGuid().ToString());
+
+            try
+            {
+                using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+                {
+
+                    if (!isoFile.DirectoryExists(LocalFolderName))
+                    {
+                        isoFile.CreateDirectory(LocalFolderName);
+                    }
+
+                    string filePath = System.IO.Path.Combine("/" + LocalFolderName + "/", filename);
+
+                    this.memoryStream.Seek(0, SeekOrigin.Begin);
+
+                    using (IsolatedStorageFileStream fileStream = isoFile.CreateFile(filePath))
+                    {
+
+                        this.memoryStream.CopyTo(fileStream);
+                    }
+
+                    AudioResult result = new AudioResult(TaskResult.OK);
+                    result.AudioFileName = filePath;
+
+                    result.AudioFile = this.memoryStream;
+                    result.AudioFile.Seek(0, SeekOrigin.Begin);
+
+                    return result;
+                }
+
+
+
+            }
+            catch (Exception)
+            {
+                //TODO: log or do something else
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Special initialization required for the microphone: XNA game loop
+        /// </summary>
+        private void InitializeXnaGameLoop()
+        {
+            // Timer to simulate the XNA game loop (Microphone is from XNA)
+            this.dtXna = new DispatcherTimer();
+            this.dtXna.Interval = TimeSpan.FromMilliseconds(33);
+            this.dtXna.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
+            this.dtXna.Start();
+        }
+        /// <summary>
+        /// Finalizes XNA game loop for microphone
+        /// </summary>
+        private void FinalizeXnaGameLoop()
+        {
+            // Timer to simulate the XNA game loop (Microphone is from XNA)
+            if (dtXna != null)
+            {
+                dtXna.Stop();
+                dtXna = null;
+            }
+        }
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml b/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml
new file mode 100644
index 0000000..a7eee21
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml
@@ -0,0 +1,26 @@
+<phone:PhoneApplicationPage 
+    x:Class="WPCordovaClassLib.Cordova.UI.ImageCapture"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    FontFamily="{StaticResource PhoneFontFamilyNormal}"
+    FontSize="{StaticResource PhoneFontSizeNormal}"
+    Foreground="{StaticResource PhoneForegroundBrush}"
+    SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
+    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
+    shell:SystemTray.IsVisible="True">
+
+    <!--LayoutRoot is the root grid where all page content is placed-->
+    <Grid x:Name="LayoutRoot" Background="Yellow">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto"/>
+            <RowDefinition Height="*"/>
+        </Grid.RowDefinitions>
+
+    </Grid>
+ 
+
+</phone:PhoneApplicationPage>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml.cs
new file mode 100644
index 0000000..234b444
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml.cs
@@ -0,0 +1,109 @@
+/*  
+	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.IO;
+using System.Windows;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+    public partial class ImageCapture : PhoneApplicationPage
+    {
+        public ImageCapture()
+        {
+            InitializeComponent();
+        }
+    }
+
+    public class ImageCaptureTask
+    {
+        /// <summary>
+        /// Represents an image returned from a call to the Show method of
+        /// a WPCordovaClassLib.Cordova.Controls.ImageCaptureTask object
+        /// </summary>
+        //public class AudioResult : TaskEventArgs
+        //{
+        //    /// <summary>
+        //    /// Initializes a new instance of the AudioResult class.
+        //    /// </summary>
+        //    public AudioResult()
+        //    { }
+
+        //    /// <summary>
+        //    /// Initializes a new instance of the AudioResult class
+        //    /// with the specified Microsoft.Phone.Tasks.TaskResult.
+        //    /// </summary>
+        //    /// <param name="taskResult">Associated Microsoft.Phone.Tasks.TaskResult</param>
+        //    public AudioResult(TaskResult taskResult)
+        //        : base(taskResult)
+        //    { }
+
+        //    /// <summary>
+        //    ///  Gets the file name of the recorded audio.
+        //    /// </summary>
+        //    public Stream AudioFile { get; internal set; }
+
+        //    /// <summary>
+        //    /// Gets the stream containing the data for the recorded audio.
+        //    /// </summary>
+        //    public string AudioFileName { get; internal set; }
+        //}
+
+        ///// <summary>
+        ///// Occurs when a audio recording task is completed.
+        ///// </summary>
+        //public event EventHandler<AudioResult> Completed;
+
+        /// <summary>
+        /// Shows Audio Recording application
+        /// </summary>
+        public void Show()
+        {
+            Deployment.Current.Dispatcher.BeginInvoke(() =>
+            {
+                var root = Application.Current.RootVisual as PhoneApplicationFrame;
+
+                root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(NavigationService_Navigated);
+
+                string baseUrl = WPCordovaClassLib.Cordova.Commands.BaseCommand.GetBaseURL();
+
+                // dummy parameter is used to always open a fresh version
+                root.Navigate(new System.Uri(baseUrl + "Cordova/UI/ImageCapture.xaml?dummy=" + Guid.NewGuid().ToString(), UriKind.Relative));
+            });
+        }
+
+        /// <summary>
+        /// Performs additional configuration of the recording application.
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void NavigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            ImageCapture imageCapture = e.Content as ImageCapture;
+            if (imageCapture != null)
+            {
+                (Application.Current.RootVisual as PhoneApplicationFrame).Navigated -= NavigationService_Navigated;
+
+                //imageCapture.Completed += this.Completed;
+                //else if (this.Completed != null)
+                //{
+                //    this.Completed(this, new AudioResult(TaskResult.Cancel));
+                //}
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml b/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml
new file mode 100644
index 0000000..1ca5d5f
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml
@@ -0,0 +1,62 @@
+<!--
+ 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. 
+-->
+<UserControl x:Class="WPCordovaClassLib.Cordova.UI.NotificationBox"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    mc:Ignorable="d"
+    FontFamily="{StaticResource PhoneFontFamilyNormal}"
+    FontSize="{StaticResource PhoneFontSizeNormal}"
+    Foreground="{StaticResource PhoneForegroundBrush}"
+    d:DesignHeight="800" d:DesignWidth="480" VerticalAlignment="Stretch">
+
+    <Grid x:Name="LayoutRoot" 
+          Background="{StaticResource PhoneSemitransparentBrush}" VerticalAlignment="Stretch">
+        
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto"/>
+            <RowDefinition Height="*"/>
+        </Grid.RowDefinitions>
+        
+
+        <!--TitlePanel contains the name of the application and page title-->
+        <StackPanel x:Name="TitlePanel" 
+                    Grid.Row="0" 
+                    Background="{StaticResource PhoneSemitransparentBrush}">
+            <TextBlock x:Name="PageTitle" 
+                       Text="Title" 
+                       Margin="10,10" 
+                       Style="{StaticResource PhoneTextTitle2Style}"/>
+            
+            <TextBlock x:Name="SubTitle" 
+                       Text="Subtitle" 
+                       TextWrapping="Wrap"
+                       Margin="10,10"
+                       Style="{StaticResource PhoneTextTitle3Style}"/>
+            
+            <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">       
+            <StackPanel x:Name="ButtonPanel"
+                        Margin="10,10"
+                        Orientation="Horizontal"/>
+            </ScrollViewer>
+
+        </StackPanel>
+    </Grid>
+</UserControl>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml.cs
new file mode 100644
index 0000000..50b2f2a
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml.cs
@@ -0,0 +1,41 @@
+/*
+ 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.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;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+    public partial class NotificationBox : UserControl
+    {
+        public NotificationBox()
+        {
+            InitializeComponent();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoCaptureTask.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoCaptureTask.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoCaptureTask.cs
new file mode 100644
index 0000000..958c05c
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoCaptureTask.cs
@@ -0,0 +1,105 @@
+/*  
+	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.IO;
+using System.Windows;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+    /// <summary>
+    /// Allows an application to launch the Video Recording application. 
+    /// Use this to allow users to record video from your application.
+    /// </summary>
+    public class VideoCaptureTask
+    {
+        /// <summary>
+        /// Represents recorded video returned from a call to the Show method of
+        /// a WPCordovaClassLib.Cordova.Controls.VideoCaptureTask object
+        /// </summary>
+        public class VideoResult : TaskEventArgs
+        {
+            /// <summary>
+            /// Initializes a new instance of the VideoResult class.
+            /// </summary>
+            public VideoResult()
+            { }
+
+            /// <summary>
+            /// Initializes a new instance of the VideoResult class
+            /// with the specified Microsoft.Phone.Tasks.TaskResult.
+            /// </summary>
+            /// <param name="taskResult">Associated Microsoft.Phone.Tasks.TaskResult</param>
+            public VideoResult(TaskResult taskResult)
+                : base(taskResult)
+            { }
+
+            /// <summary>
+            ///  Gets the file name of the recorded Video.
+            /// </summary>
+            public Stream VideoFile { get; internal set; }
+
+            /// <summary>
+            /// Gets the stream containing the data for the recorded Video.
+            /// </summary>
+            public string VideoFileName { get; internal set; }
+        }
+
+        /// <summary>
+        /// Occurs when a Video recording task is completed.
+        /// </summary>
+        public event EventHandler<VideoResult> Completed;
+
+        /// <summary>
+        /// Shows Video Recording application
+        /// </summary>
+        public void Show()
+        {
+            Deployment.Current.Dispatcher.BeginInvoke(() =>
+            {
+                var root = Application.Current.RootVisual as PhoneApplicationFrame;
+
+                root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(NavigationService_Navigated);
+
+                string baseUrl = WPCordovaClassLib.Cordova.Commands.BaseCommand.GetBaseURL();
+                // dummy parameter is used to always open a fresh version
+                root.Navigate(new System.Uri( baseUrl + "CordovaLib/UI/VideoRecorder.xaml?dummy=" + Guid.NewGuid().ToString(), UriKind.Relative));
+            });
+        }
+
+        /// <summary>
+        /// Performs additional configuration of the recording application.
+        /// </summary>
+        private void NavigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            if (!(e.Content is VideoRecorder)) return;
+
+            (Application.Current.RootVisual as PhoneApplicationFrame).Navigated -= NavigationService_Navigated;
+
+            VideoRecorder VideoRecorder = (VideoRecorder)e.Content;
+
+            if (VideoRecorder != null)
+            {
+                VideoRecorder.Completed += this.Completed;
+            }
+            else if (this.Completed != null)
+            {
+                this.Completed(this, new VideoResult(TaskResult.Cancel));
+            }
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml
new file mode 100644
index 0000000..c78fdb0
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml
@@ -0,0 +1,52 @@
+<!--
+ 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. 
+-->
+<phone:PhoneApplicationPage 
+    x:Class="WPCordovaClassLib.Cordova.UI.VideoRecorder"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="480"
+    FontFamily="{StaticResource PhoneFontFamilyNormal}"
+    FontSize="{StaticResource PhoneFontSizeNormal}"
+    Foreground="{StaticResource PhoneForegroundBrush}"
+    SupportedOrientations="Landscape" Orientation="LandscapeLeft"
+    shell:SystemTray.IsVisible="False">
+   
+    <Canvas x:Name="LayoutRoot" Background="Transparent" Grid.ColumnSpan="1" Grid.Column="0">
+
+        <Rectangle 
+            x:Name="viewfinderRectangle"
+            Width="640" 
+            Height="480" 
+            HorizontalAlignment="Left" 
+            Canvas.Left="80"/>
+        
+    </Canvas>
+
+    <phone:PhoneApplicationPage.ApplicationBar>
+        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" x:Name="PhoneAppBar" Opacity="0.0">
+            <shell:ApplicationBarIconButton IconUri="/Images/appbar.feature.video.rest.png" Text="Record"  x:Name="btnStartRecording" Click="StartRecording_Click" />
+            <shell:ApplicationBarIconButton IconUri="/Images/appbar.save.rest.png" Text="Take" x:Name="btnTakeVideo" Click="TakeVideo_Click"/>            
+        </shell:ApplicationBar>
+    </phone:PhoneApplicationPage.ApplicationBar>
+
+</phone:PhoneApplicationPage>