Thu, 04 Jun 2015 14:50:33 +0200
Genesis of lecture sources for Droidcon Berlin 2015 in Postbahnhof.
1 /*
2 Licensed under the Apache License, Version 2.0 (the "License");
3 you may not use this file except in compliance with the License.
4 You may obtain a copy of the License at
6 http://www.apache.org/licenses/LICENSE-2.0
8 Unless required by applicable law or agreed to in writing, software
9 distributed under the License is distributed on an "AS IS" BASIS,
10 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 See the License for the specific language governing permissions and
12 limitations under the License.
13 */
15 using System;
16 using System.Windows;
17 using System.Windows.Controls;
18 using Microsoft.Devices;
19 using System.Runtime.Serialization;
20 using System.Threading;
21 using System.Windows.Resources;
22 using Microsoft.Phone.Controls;
23 using Microsoft.Xna.Framework.Audio;
24 using WPCordovaClassLib.Cordova.UI;
25 using System.Diagnostics;
28 namespace WPCordovaClassLib.Cordova.Commands
29 {
30 public class Notification : BaseCommand
31 {
32 static ProgressBar progressBar = null;
33 const int DEFAULT_DURATION = 5;
35 private NotificationBox notifyBox;
37 private class NotifBoxData
38 {
39 public NotificationBox previous {get;set;}
40 public string callbackId { get; set; }
41 }
43 private PhoneApplicationPage Page
44 {
45 get
46 {
47 PhoneApplicationPage page = null;
48 PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
49 if (frame != null)
50 {
51 page = frame.Content as PhoneApplicationPage;
52 }
53 return page;
54 }
55 }
57 // blink api - doesn't look like there is an equivalent api we can use...
59 [DataContract]
60 public class AlertOptions
61 {
62 [OnDeserializing]
63 public void OnDeserializing(StreamingContext context)
64 {
65 // set defaults
66 this.message = "message";
67 this.title = "Alert";
68 this.buttonLabel = "ok";
69 }
71 /// <summary>
72 /// message to display in the alert box
73 /// </summary>
74 [DataMember]
75 public string message;
77 /// <summary>
78 /// title displayed on the alert window
79 /// </summary>
80 [DataMember]
81 public string title;
83 /// <summary>
84 /// text to display on the button
85 /// </summary>
86 [DataMember]
87 public string buttonLabel;
88 }
90 [DataContract]
91 public class PromptResult
92 {
93 [DataMember]
94 public int buttonIndex;
96 [DataMember]
97 public string input1;
99 public PromptResult(int index, string text)
100 {
101 this.buttonIndex = index;
102 this.input1 = text;
103 }
104 }
106 public void alert(string options)
107 {
108 string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
109 AlertOptions alertOpts = new AlertOptions();
110 alertOpts.message = args[0];
111 alertOpts.title = args[1];
112 alertOpts.buttonLabel = args[2];
113 string aliasCurrentCommandCallbackId = args[3];
115 Deployment.Current.Dispatcher.BeginInvoke(() =>
116 {
117 PhoneApplicationPage page = Page;
118 if (page != null)
119 {
120 Grid grid = page.FindName("LayoutRoot") as Grid;
121 if (grid != null)
122 {
123 var previous = notifyBox;
124 notifyBox = new NotificationBox();
125 notifyBox.Tag = new NotifBoxData { previous = previous, callbackId = aliasCurrentCommandCallbackId };
126 notifyBox.PageTitle.Text = alertOpts.title;
127 notifyBox.SubTitle.Text = alertOpts.message;
128 Button btnOK = new Button();
129 btnOK.Content = alertOpts.buttonLabel;
130 btnOK.Click += new RoutedEventHandler(btnOK_Click);
131 btnOK.Tag = 1;
132 notifyBox.ButtonPanel.Children.Add(btnOK);
133 grid.Children.Add(notifyBox);
135 if (previous == null)
136 {
137 page.BackKeyPress += page_BackKeyPress;
138 }
139 }
140 }
141 else
142 {
143 DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION));
144 }
145 });
146 }
148 public void prompt(string options)
149 {
150 string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
151 string message = args[0];
152 string title = args[1];
153 string buttonLabelsArray = args[2];
154 string[] buttonLabels = JSON.JsonHelper.Deserialize<string[]>(buttonLabelsArray);
155 string defaultText = args[3];
156 string aliasCurrentCommandCallbackId = args[4];
158 Deployment.Current.Dispatcher.BeginInvoke(() =>
159 {
160 PhoneApplicationPage page = Page;
161 if (page != null)
162 {
163 Grid grid = page.FindName("LayoutRoot") as Grid;
164 if (grid != null)
165 {
166 var previous = notifyBox;
167 notifyBox = new NotificationBox();
168 notifyBox.Tag = new NotifBoxData { previous = previous, callbackId = aliasCurrentCommandCallbackId };
169 notifyBox.PageTitle.Text = title;
170 notifyBox.SubTitle.Text = message;
172 //TextBox textBox = new TextBox();
173 //textBox.Text = defaultText;
174 //textBox.AcceptsReturn = true;
175 //notifyBox.ContentScroller.Content = textBox;
177 notifyBox.InputText.Text = defaultText;
178 notifyBox.InputText.Visibility = Visibility.Visible;
180 for (int i = 0; i < buttonLabels.Length; ++i)
181 {
182 Button button = new Button();
183 button.Content = buttonLabels[i];
184 button.Tag = i + 1;
185 button.Click += promptBoxbutton_Click;
186 notifyBox.ButtonPanel.Orientation = Orientation.Vertical;
187 notifyBox.ButtonPanel.Children.Add(button);
188 }
190 grid.Children.Add(notifyBox);
191 if (previous != null)
192 {
193 page.BackKeyPress += page_BackKeyPress;
194 }
195 }
196 }
197 else
198 {
199 DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION));
200 }
201 });
202 }
204 public void confirm(string options)
205 {
206 string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
207 AlertOptions alertOpts = new AlertOptions();
208 alertOpts.message = args[0];
209 alertOpts.title = args[1];
210 alertOpts.buttonLabel = args[2];
211 string aliasCurrentCommandCallbackId = args[3];
213 Deployment.Current.Dispatcher.BeginInvoke(() =>
214 {
215 PhoneApplicationPage page = Page;
216 if (page != null)
217 {
218 Grid grid = page.FindName("LayoutRoot") as Grid;
219 if (grid != null)
220 {
221 var previous = notifyBox;
222 notifyBox = new NotificationBox();
223 notifyBox.Tag = new NotifBoxData { previous = previous, callbackId = aliasCurrentCommandCallbackId };
224 notifyBox.PageTitle.Text = alertOpts.title;
225 notifyBox.SubTitle.Text = alertOpts.message;
227 string[] labels = JSON.JsonHelper.Deserialize<string[]>(alertOpts.buttonLabel);
229 if (labels == null)
230 {
231 labels = alertOpts.buttonLabel.Split(',');
232 }
234 for (int n = 0; n < labels.Length; n++)
235 {
236 Button btn = new Button();
237 btn.Content = labels[n];
238 btn.Tag = n;
239 btn.Click += new RoutedEventHandler(btnOK_Click);
240 notifyBox.ButtonPanel.Children.Add(btn);
241 }
243 grid.Children.Add(notifyBox);
244 if (previous == null)
245 {
246 page.BackKeyPress += page_BackKeyPress;
247 }
248 }
249 }
250 else
251 {
252 DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION));
253 }
254 });
255 }
257 void promptBoxbutton_Click(object sender, RoutedEventArgs e)
258 {
259 Button button = sender as Button;
260 FrameworkElement promptBox = null;
261 int buttonIndex = 0;
262 string callbackId = string.Empty;
263 string text = string.Empty;
264 if (button != null)
265 {
266 buttonIndex = (int)button.Tag;
267 promptBox = button.Parent as FrameworkElement;
268 while ((promptBox = promptBox.Parent as FrameworkElement) != null &&
269 !(promptBox is NotificationBox)) ;
270 }
272 if (promptBox != null)
273 {
274 NotificationBox box = promptBox as NotificationBox;
276 text = box.InputText.Text;
278 PhoneApplicationPage page = Page;
279 if (page != null)
280 {
281 Grid grid = page.FindName("LayoutRoot") as Grid;
282 if (grid != null)
283 {
284 grid.Children.Remove(promptBox);
285 }
287 NotifBoxData data = promptBox.Tag as NotifBoxData;
288 promptBox = data.previous as NotificationBox;
289 callbackId = data.callbackId as string;
291 if (promptBox == null)
292 {
293 page.BackKeyPress -= page_BackKeyPress;
294 }
295 }
296 }
297 DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new PromptResult(buttonIndex, text)), callbackId);
298 }
300 void page_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
301 {
302 PhoneApplicationPage page = sender as PhoneApplicationPage;
303 string callbackId = "";
304 if (page != null && notifyBox != null)
305 {
306 Grid grid = page.FindName("LayoutRoot") as Grid;
307 if (grid != null)
308 {
309 grid.Children.Remove(notifyBox);
310 NotifBoxData notifBoxData = notifyBox.Tag as NotifBoxData;
311 notifyBox = notifBoxData.previous as NotificationBox;
312 callbackId = notifBoxData.callbackId as string;
313 }
314 if (notifyBox == null)
315 {
316 page.BackKeyPress -= page_BackKeyPress;
317 }
318 e.Cancel = true;
319 }
321 DispatchCommandResult(new PluginResult(PluginResult.Status.OK, 0), callbackId);
322 }
324 void btnOK_Click(object sender, RoutedEventArgs e)
325 {
326 Button btn = sender as Button;
327 FrameworkElement notifBoxParent = null;
328 int retVal = 0;
329 string callbackId = "";
330 if (btn != null)
331 {
332 retVal = (int)btn.Tag + 1;
334 notifBoxParent = btn.Parent as FrameworkElement;
335 while ((notifBoxParent = notifBoxParent.Parent as FrameworkElement) != null &&
336 !(notifBoxParent is NotificationBox)) ;
337 }
338 if (notifBoxParent != null)
339 {
340 PhoneApplicationPage page = Page;
341 if (page != null)
342 {
343 Grid grid = page.FindName("LayoutRoot") as Grid;
344 if (grid != null)
345 {
346 grid.Children.Remove(notifBoxParent);
347 }
349 NotifBoxData notifBoxData = notifBoxParent.Tag as NotifBoxData;
350 notifyBox = notifBoxData.previous as NotificationBox;
351 callbackId = notifBoxData.callbackId as string;
353 if (notifyBox == null)
354 {
355 page.BackKeyPress -= page_BackKeyPress;
356 }
357 }
359 }
360 DispatchCommandResult(new PluginResult(PluginResult.Status.OK, retVal), callbackId);
361 }
365 public void beep(string options)
366 {
367 string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
368 int times = int.Parse(args[0]);
370 string resourcePath = BaseCommand.GetBaseURL() + "Plugins/org.apache.cordova.dialogs/notification-beep.wav";
372 StreamResourceInfo sri = Application.GetResourceStream(new Uri(resourcePath, UriKind.Relative));
374 if (sri != null)
375 {
376 SoundEffect effect = SoundEffect.FromStream(sri.Stream);
377 SoundEffectInstance inst = effect.CreateInstance();
378 ThreadPool.QueueUserWorkItem((o) =>
379 {
380 // cannot interact with UI !!
381 do
382 {
383 inst.Play();
384 Thread.Sleep(effect.Duration + TimeSpan.FromMilliseconds(100));
385 }
386 while (--times > 0);
388 });
390 }
392 // TODO: may need a listener to trigger DispatchCommandResult after the alarm has finished executing...
393 DispatchCommandResult();
394 }
396 // Display an indeterminate progress indicator
397 public void activityStart(string unused)
398 {
400 Deployment.Current.Dispatcher.BeginInvoke(() =>
401 {
402 PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
404 if (frame != null)
405 {
406 PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
408 if (page != null)
409 {
410 var temp = page.FindName("LayoutRoot");
411 Grid grid = temp as Grid;
412 if (grid != null)
413 {
414 if (progressBar != null)
415 {
416 grid.Children.Remove(progressBar);
417 }
418 progressBar = new ProgressBar();
419 progressBar.IsIndeterminate = true;
420 progressBar.IsEnabled = true;
422 grid.Children.Add(progressBar);
423 }
424 }
425 }
426 });
427 }
430 // Remove our indeterminate progress indicator
431 public void activityStop(string unused)
432 {
433 Deployment.Current.Dispatcher.BeginInvoke(() =>
434 {
435 if (progressBar != null)
436 {
437 progressBar.IsEnabled = false;
438 PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
439 if (frame != null)
440 {
441 PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
442 if (page != null)
443 {
444 Grid grid = page.FindName("LayoutRoot") as Grid;
445 if (grid != null)
446 {
447 grid.Children.Remove(progressBar);
448 }
449 }
450 }
451 progressBar = null;
452 }
453 });
454 }
456 public void vibrate(string vibrateDuration)
457 {
459 int msecs = 200; // set default
461 try
462 {
463 string[] args = JSON.JsonHelper.Deserialize<string[]>(vibrateDuration);
465 msecs = int.Parse(args[0]);
466 if (msecs < 1)
467 {
468 msecs = 1;
469 }
470 }
471 catch (FormatException)
472 {
474 }
476 VibrateController.Default.Start(TimeSpan.FromMilliseconds(msecs));
478 // TODO: may need to add listener to trigger DispatchCommandResult when the vibration ends...
479 DispatchCommandResult();
480 }
481 }
482 }