iOS and Android timers should be runnable from any thread and execute… (#374)
authoradrianknight89 <adrianknight89@outlook.com>
Wed, 11 Jan 2017 00:07:01 +0000 (18:07 -0600)
committerJason Smith <jason.smith@xamarin.com>
Wed, 11 Jan 2017 00:07:01 +0000 (16:07 -0800)
* iOS and Android timers should be runnable from any thread and executed on the main thread

* removing unused Timer class declarations with minor refactoring efforts

* iOS and Android timers should be runnable from any thread and executed on the main thread

* removing bak file

* switch to v7

* add test code

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla28953.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Core.UnitTests/MockPlatformServices.cs
Xamarin.Forms.Core/ITimer.cs [deleted file]
Xamarin.Forms.Core/Xamarin.Forms.Core.csproj
Xamarin.Forms.Platform.Android/Forms.cs
Xamarin.Forms.Platform.WP8/WP8PlatformServices.cs
Xamarin.Forms.Platform.WinRT/WindowsBasePlatformServices.cs
Xamarin.Forms.Platform.iOS/Forms.cs

diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla28953.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla28953.cs
new file mode 100644 (file)
index 0000000..3a35786
--- /dev/null
@@ -0,0 +1,116 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+using System;
+using System.Threading.Tasks;
+
+#if UITEST
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Bugzilla, 28953, "Device.StartTimer (still) behaves differently on different platforms", PlatformAffected.All)]
+       public class Bugzilla28953 : TestContentPage // or TestMasterDetailPage, etc ...
+       {
+               int count = 0, count2 = 0;
+               Label label2, label3;
+               bool shouldStop, shouldStop2;
+
+               protected override void Init()
+               {
+                       var stackLayout = new StackLayout
+                       {
+                               Orientation = StackOrientation.Vertical,
+                               VerticalOptions = LayoutOptions.Center,
+                               Spacing = 20
+                       };
+
+                       var label1 = new Label
+                       {
+                               Text = "Click Start to start counting with a timer. Click Stop to reset. Both timers update text in UI thread."
+                       };
+                       stackLayout.Children.Add(label1);
+
+                       label2 = new Label
+                       {
+                               Text = count.ToString(),
+                               HorizontalTextAlignment = TextAlignment.Center,
+                       };
+                       stackLayout.Children.Add(label2);
+
+                       label3 = new Label
+                       {
+                               Text = count2.ToString(),
+                               HorizontalTextAlignment = TextAlignment.Center,
+                       };
+                       stackLayout.Children.Add(label3);
+
+                       var button = new Button
+                       {
+                               Text = "Start"
+                       };
+                       button.Clicked += Button_Clicked;
+                       stackLayout.Children.Add(button);
+
+                       var button2 = new Button
+                       {
+                               Text = "Start (in background thread)"
+                       };
+                       button2.Clicked += Button_Clicked2;
+                       stackLayout.Children.Add(button2);
+
+                       Content = stackLayout;
+               }
+
+               private void Button_Clicked(object sender, EventArgs e)
+               {
+                       var button = sender as Button;
+                       if (button.Text == "Start")
+                       {
+                               (sender as Button).Text = "Stop";
+                               shouldStop = false;
+
+                               Device.StartTimer(TimeSpan.FromMilliseconds(100), () =>
+                               {
+                                       label2.Text = count.ToString();
+                                       count++;
+                                       return !shouldStop;
+                               });
+                       }
+                       else
+                       {
+                               button.Text = "Start";
+                               shouldStop = true;
+                               count = 0;
+                       }
+               }
+
+               private void Button_Clicked2(object sender, EventArgs e)
+               {
+                       var button = sender as Button;
+                       if (button.Text == "Start (in background thread)")
+                       {
+                               (sender as Button).Text = "Stop (in background thread)";
+                               shouldStop2 = false;
+
+                               Task.Run(() =>
+                               {
+                                       Device.StartTimer(TimeSpan.FromMilliseconds(100), () =>
+                                       {
+                                               label3.Text = count2.ToString();
+                                               count2++;
+                                               return !shouldStop2;
+                                       });
+                               });
+                       }
+                       else
+                       {
+                               button.Text = "Start (in background thread)";
+                               shouldStop2 = true;
+                               count2 = 0;
+                       }
+               }
+       }
+}
\ No newline at end of file
index 36ed04c..16a2199 100644 (file)
@@ -36,6 +36,7 @@
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla28570.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla28796.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla28939.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Bugzilla28953.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla29107.xaml.cs">
       <DependentUpon>Bugzilla29107.xaml</DependentUpon>
     </Compile>
index 5109cbb..e8519b9 100644 (file)
@@ -119,57 +119,6 @@ namespace Xamarin.Forms.Core.UnitTests
                        return AppDomain.CurrentDomain.GetAssemblies ();
                }
 
-               public ITimer CreateTimer (Action<object> callback)
-               {
-                       return new MockTimer (new Timer (o => callback(o)));
-               }
-
-               public ITimer CreateTimer (Action<object> callback, object state, int dueTime, int period)
-               {
-                       return new MockTimer (new Timer (o => callback(o), state, dueTime, period));
-               }
-
-               public ITimer CreateTimer (Action<object> callback, object state, long dueTime, long period)
-               {
-                       return new MockTimer (new Timer (o => callback(o), state, dueTime, period));
-               }
-
-               public ITimer CreateTimer (Action<object> callback, object state, TimeSpan dueTime, TimeSpan period)
-               {
-                       return new MockTimer (new Timer (o => callback(o), state, dueTime, period));
-               }
-
-               public ITimer CreateTimer (Action<object> callback, object state, uint dueTime, uint period)
-               {
-                       return new MockTimer (new Timer (o => callback(o), state, dueTime, period));
-               }
-
-               public class MockTimer : ITimer
-               {
-                       readonly Timer timer;
-                       public MockTimer (Timer timer)
-                       {
-                               this.timer = timer;
-                       }
-
-                       public void Change (int dueTime, int period)
-                       {
-                               timer.Change (dueTime, period);
-                       }
-                       public void Change (long dueTime, long period)
-                       {
-                               timer.Change (dueTime, period);
-                       }
-                       public void Change (TimeSpan dueTime, TimeSpan period)
-                       {
-                               timer.Change (dueTime, period);
-                       }
-                       public void Change (uint dueTime, uint period)
-                       {
-                               timer.Change (dueTime, period);
-                       }
-               }
-
                public IIsolatedStorageFile GetUserStoreForApplication ()
                {
 #if WINDOWS_PHONE
diff --git a/Xamarin.Forms.Core/ITimer.cs b/Xamarin.Forms.Core/ITimer.cs
deleted file mode 100644 (file)
index ba867db..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-
-namespace Xamarin.Forms
-{
-       //this will go once Timer is included in Pcl profiles
-       internal interface ITimer
-       {
-               void Change(int dueTime, int period);
-               void Change(long dueTime, long period);
-               void Change(TimeSpan dueTime, TimeSpan period);
-               void Change(uint dueTime, uint period);
-       }
-}
\ No newline at end of file
index 9bfb7ba..2e10a1b 100644 (file)
     <Compile Include="Tweener.cs" />
     <Compile Include="IPlatformServices.cs" />
     <Compile Include="UriTypeConverter.cs" />
-    <Compile Include="ITimer.cs" />
     <Compile Include="IIsolatedStorageFile.cs" />
     <Compile Include="Grid.cs" />
     <Compile Include="GridCalc.cs" />
index 3d2a735..1ecf76d 100644 (file)
@@ -410,22 +410,15 @@ namespace Xamarin.Forms
 
                        public void StartTimer(TimeSpan interval, Func<bool> callback)
                        {
-                               Timer timer = null;
-                               bool invoking = false;
-                               TimerCallback onTimeout = o =>
+                               var handler = new Handler(Looper.MainLooper);
+                               handler.PostDelayed(() =>
                                {
-                                       if (!invoking)
-                                       {
-                                               invoking = true;
-                                               BeginInvokeOnMainThread(() =>
-                                               {
-                                                       if (!callback())
-                                                               timer.Dispose();
-                                                       invoking = false;
-                                               });
-                                       }
-                               };
-                               timer = new Timer(onTimeout, null, interval, interval);
+                                       if (callback())
+                                               StartTimer(interval, callback);
+
+                                       handler.Dispose();
+                                       handler = null;
+                               }, (long)interval.TotalMilliseconds);
                        }
 
                        double ConvertTextAppearanceToSize(int themeDefault, int deviceDefault, double defaultValue)
@@ -472,36 +465,6 @@ namespace Xamarin.Forms
                                return false;
                        }
 
-                       public class _Timer : ITimer
-                       {
-                               readonly Timer _timer;
-
-                               public _Timer(Timer timer)
-                               {
-                                       _timer = timer;
-                               }
-
-                               public void Change(int dueTime, int period)
-                               {
-                                       _timer.Change(dueTime, period);
-                               }
-
-                               public void Change(long dueTime, long period)
-                               {
-                                       _timer.Change(dueTime, period);
-                               }
-
-                               public void Change(TimeSpan dueTime, TimeSpan period)
-                               {
-                                       _timer.Change(dueTime, period);
-                               }
-
-                               public void Change(uint dueTime, uint period)
-                               {
-                                       _timer.Change(dueTime, period);
-                               }
-                       }
-
                        public class _IsolatedStorageFile : IIsolatedStorageFile
                        {
                                readonly IsolatedStorageFile _isolatedStorageFile;
index 3062308..cd9f44f 100644 (file)
@@ -137,36 +137,6 @@ namespace Xamarin.Forms
                        return 'a' + v - 10;
                }
 
-               public class _Timer : ITimer
-               {
-                       readonly Timer _timer;
-
-                       public _Timer(Timer timer)
-                       {
-                               _timer = timer;
-                       }
-
-                       public void Change(int dueTime, int period)
-                       {
-                               _timer.Change(dueTime, period);
-                       }
-
-                       public void Change(long dueTime, long period)
-                       {
-                               _timer.Change(dueTime, period);
-                       }
-
-                       public void Change(TimeSpan dueTime, TimeSpan period)
-                       {
-                               _timer.Change(dueTime, period);
-                       }
-
-                       public void Change(uint dueTime, uint period)
-                       {
-                               _timer.Change(dueTime, period);
-                       }
-               }
-
                public class _IsolatedStorageFile : IIsolatedStorageFile
                {
                        readonly IsolatedStorageFile _isolatedStorageFile;
index 49589a8..310b66c 100644 (file)
@@ -29,12 +29,12 @@ namespace Xamarin.Forms.Platform.WinRT
 {
        internal abstract class WindowsBasePlatformServices : IPlatformServices
        {
-               CoreDispatcher _dispatcher;
+               readonly CoreDispatcher _dispatcher;
 
-               public WindowsBasePlatformServices(CoreDispatcher dispatcher)
+               protected WindowsBasePlatformServices(CoreDispatcher dispatcher)
                {
                        if (dispatcher == null)
-                               throw new ArgumentNullException("dispatcher");
+                               throw new ArgumentNullException(nameof(dispatcher));
 
                        _dispatcher = dispatcher;
                }
@@ -57,9 +57,8 @@ namespace Xamarin.Forms.Platform.WinRT
                        IReadOnlyList<StorageFile> files = query.GetFilesAsync().AsTask().Result;
 
                        var assemblies = new List<Assembly>(files.Count);
-                       for (var i = 0; i < files.Count; i++)
+                       foreach (StorageFile file in files)
                        {
-                               StorageFile file = files[i];
                                try
                                {
                                        Assembly assembly = Assembly.Load(new AssemblyName { Name = Path.GetFileNameWithoutExtension(file.Name) });
@@ -133,35 +132,5 @@ namespace Xamarin.Forms.Platform.WinRT
                                        timer.Stop();
                        };
                }
-
-               internal class WindowsTimer : ITimer
-               {
-                       readonly Timer _timer;
-
-                       public WindowsTimer(Timer timer)
-                       {
-                               _timer = timer;
-                       }
-
-                       public void Change(int dueTime, int period)
-                       {
-                               _timer.Change(dueTime, period);
-                       }
-
-                       public void Change(long dueTime, long period)
-                       {
-                               Change(TimeSpan.FromMilliseconds(dueTime), TimeSpan.FromMilliseconds(period));
-                       }
-
-                       public void Change(TimeSpan dueTime, TimeSpan period)
-                       {
-                               _timer.Change(dueTime, period);
-                       }
-
-                       public void Change(uint dueTime, uint period)
-                       {
-                               Change(TimeSpan.FromMilliseconds(dueTime), TimeSpan.FromMilliseconds(period));
-                       }
-               }
        }
 }
\ No newline at end of file
index 06cb131..5361e13 100644 (file)
@@ -68,9 +68,7 @@ namespace Xamarin.Forms
 
                internal static void SendViewInitialized(this VisualElement self, UIView nativeView)
                {
-                       var viewInitialized = ViewInitialized;
-                       if (viewInitialized != null)
-                               viewInitialized(self, new ViewInitializedEventArgs { View = self, NativeView = nativeView });
+                       ViewInitialized?.Invoke(self, new ViewInitializedEventArgs { View = self, NativeView = nativeView });
                }
 
                class iOSExpressionSearch : ExpressionVisitor, IExpressionSearch
@@ -117,15 +115,9 @@ namespace Xamarin.Forms
 
                        public override Size PixelScreenSize { get; }
 
-                       public override Size ScaledScreenSize
-                       {
-                               get { return _scaledScreenSize; }
-                       }
+                       public override Size ScaledScreenSize => _scaledScreenSize;
 
-                       public override double ScalingFactor
-                       {
-                               get { return _scalingFactor; }
-                       }
+                       public override double ScalingFactor => _scalingFactor;
 
                        protected override void Dispose(bool disposing)
                        {
@@ -136,7 +128,7 @@ namespace Xamarin.Forms
 
                class IOSPlatformServices : IPlatformServices
                {
-                       static readonly MD5CryptoServiceProvider Checksum = new MD5CryptoServiceProvider();
+                       static readonly MD5CryptoServiceProvider s_checksum = new MD5CryptoServiceProvider();
 
                        public void BeginInvokeOnMainThread(Action action)
                        {
@@ -155,7 +147,7 @@ namespace Xamarin.Forms
 
                        public string GetMD5Hash(string input)
                        {
-                               var bytes = Checksum.ComputeHash(Encoding.UTF8.GetBytes(input));
+                               var bytes = s_checksum.ComputeHash(Encoding.UTF8.GetBytes(input));
                                var ret = new char[32];
                                for (var i = 0; i < 16; i++)
                                {
@@ -198,10 +190,7 @@ namespace Xamarin.Forms
                                return new _IsolatedStorageFile(IsolatedStorageFile.GetUserStoreForApplication());
                        }
 
-                       public bool IsInvokeRequired
-                       {
-                               get { return !NSThread.IsMain; }
-                       }
+                       public bool IsInvokeRequired => !NSThread.IsMain;
 
                        public void OpenUriAction(Uri uri)
                        {
@@ -210,8 +199,7 @@ namespace Xamarin.Forms
 
                        public void StartTimer(TimeSpan interval, Func<bool> callback)
                        {
-                               NSTimer timer = null;
-                               timer = NSTimer.CreateRepeatingScheduledTimer(interval, t =>
+                               NSTimer timer = NSTimer.CreateRepeatingTimer(interval, t =>
                                {
                                        if (!callback())
                                                t.Invalidate();
@@ -238,36 +226,6 @@ namespace Xamarin.Forms
                                return 'a' + v - 10;
                        }
 
-                       public class _Timer : ITimer
-                       {
-                               readonly Timer _timer;
-
-                               public _Timer(Timer timer)
-                               {
-                                       _timer = timer;
-                               }
-
-                               public void Change(int dueTime, int period)
-                               {
-                                       _timer.Change(dueTime, period);
-                               }
-
-                               public void Change(long dueTime, long period)
-                               {
-                                       _timer.Change(dueTime, period);
-                               }
-
-                               public void Change(TimeSpan dueTime, TimeSpan period)
-                               {
-                                       _timer.Change(dueTime, period);
-                               }
-
-                               public void Change(uint dueTime, uint period)
-                               {
-                                       _timer.Change(dueTime, period);
-                               }
-                       }
-
                        public class _IsolatedStorageFile : IIsolatedStorageFile
                        {
                                readonly IsolatedStorageFile _isolatedStorageFile;