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>