forked from unoplatform/uno
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBaseActivity.Android.cs
More file actions
340 lines (285 loc) · 8.59 KB
/
Copy pathBaseActivity.Android.cs
File metadata and controls
340 lines (285 loc) · 8.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Uno.Disposables;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.UI.Core;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Uno.Diagnostics.Eventing;
using Uno.Extensions;
using Uno.Logging;
using Windows.UI.Xaml;
using Android.OS;
namespace Uno.UI
{
[Activity(
// This is required for OnConfigurationChanges to be raised.
ConfigurationChanges=
Android.Content.PM.ConfigChanges.Orientation
| Android.Content.PM.ConfigChanges.ScreenSize
)]
#pragma warning disable 618
public partial class BaseActivity : Android.Support.V7.App.AppCompatActivity, DependencyObject
#pragma warning restore 618
{
public static class TraceProvider
{
public readonly static Guid Id = Guid.Parse("{D3D9799C-E65D-4A71-AE1E-1A3CB77B2492}");
public const int TouchStart = 1;
public const int TouchStop = 2;
}
private readonly static IEventProvider _trace = Tracing.Get(TraceProvider.Id);
public const string CreatedTotalBindableActivityCounter = "BindableActivity.CreatedTotal";
public const string ActiveBindableActivityCounter = "BindableActivity.ActiveCount";
public const string DisposedTotalBindableActivityCounter = "BindableActivity.DisposedCount";
static BaseActivity()
{
Windows.UI.Xaml.GenericStyles.Initialize();
}
/// <summary>
/// Occurs when an instance of BaseActivity is created or destroyed
/// </summary>
public static event EventHandler<ActivitiesCollectionChangedEventArgs> InstancesChanged;
/// <summary>
/// Occurs when the <see cref="Current"/> activity changed.
/// </summary>
public static event EventHandler<CurrentActivityChangedEventArgs> CurrentChanged;
private static int _instanceCount = 0;
private static IImmutableDictionary<int, BaseActivity> _instances = ImmutableDictionary<int, BaseActivity>.Empty;
private static BaseActivity _current;
/// <summary>
/// Unique identifier for this instance of an activity.
/// </summary>
public int Id { get; } = Interlocked.Increment(ref _instanceCount);
/// <summary>
/// Gets a list of all activities which are currenlty alive.
/// </summary>
public static IImmutableDictionary<int, BaseActivity> Instances => _instances;
/// <summary>
/// Gets the currently running activity, if any.
/// <remarks>
/// This is the BaseActivity which is currently running, which means that it was "Resumed" and not "Paused".
/// This may be null if the current activity does not inherit from BaseActivity, or is not yet "Created".
/// For more info look at the lifecycle diagram documented here: https://developer.android.com/reference/android/app/Activity.html.
/// </remarks>
/// </summary>
public static BaseActivity Current => _current;
/// <summary>
/// Gets the first BaseActivity which is set as current. Unlike the <see cref="Current"/>, this method will wait until a BaseActivity is set as Current.
/// </summary>
/// <param name="ct"></param>
/// <returns>The first BaseActivity displayed</returns>
public static async Task<BaseActivity> GetCurrent(CancellationToken ct)
{
// Fast path
var current = Current;
if (current != null)
{
return current;
}
var asyncCurrent = new TaskCompletionSource<BaseActivity>();
var handler = new EventHandler<CurrentActivityChangedEventArgs>((cnd, args) =>
{
if (args.Current != null)
{
asyncCurrent.TrySetResult(args.Current);
}
});
try
{
CurrentChanged += handler;
// Check if updated since initial check
current = Current;
if (current != null)
{
return current;
}
using (ct.Register(() => asyncCurrent.TrySetCanceled()))
{
return await asyncCurrent.Task;
}
}
finally
{
CurrentChanged -= handler;
}
}
public BaseActivity(IntPtr handle, JniHandleOwnership transfer)
: base(handle, transfer)
{
InitializeBinder();
ContextHelper.Current = this;
NotifyCreatingInstance();
#if !IS_UNO
Performance.Increment(CreatedTotalBindableActivityCounter);
Performance.Increment(ActiveBindableActivityCounter);
#endif
}
public BaseActivity()
{
InitializeBinder();
ContextHelper.Current = this;
NotifyCreatingInstance();
#if !IS_UNO
Performance.Increment(CreatedTotalBindableActivityCounter);
Performance.Increment(ActiveBindableActivityCounter);
#endif
}
partial void InnerAttachedToWindow() => BinderAttachedToWindow();
partial void InnerDetachedFromWindow() => BinderDetachedFromWindow();
public View ContentView { get; private set; }
public override void SetContentView(View view)
{
ContentView = view;
base.SetContentView(view);
}
public override void SetContentView(View view, ViewGroup.LayoutParams @params)
{
ContentView = view;
base.SetContentView(view, @params);
}
public override void AddContentView(View view, ViewGroup.LayoutParams @params)
{
ContentView = view;
base.AddContentView(view, @params);
}
#region Activity LifeCycle cf. https://developer.android.com/reference/android/app/Activity.html
partial void InnerCreate(Android.OS.Bundle bundle) => SetAsCurrent();
partial void InnerCreateWithPersistedState(Android.OS.Bundle bundle, PersistableBundle persistentState) => SetAsCurrent();
partial void InnerStart() => SetAsCurrent();
partial void InnerRestart() => SetAsCurrent();
partial void InnerResume()
{
SetAsCurrent();
Windows.UI.Xaml.Application.Current?.OnResuming();
}
partial void InnerPause()
{
ResignCurrent();
Windows.UI.Xaml.Application.Current?.OnSuspending();
}
partial void InnerStop() => ResignCurrent();
partial void InnerDestroy() => ResignCurrent();
private void SetAsCurrent()
{
ContextHelper.Current = this;
if (Interlocked.Exchange(ref _current, this) != this)
{
_current = this;
CurrentChanged?.Invoke(this, new CurrentActivityChangedEventArgs(this));
}
}
private void ResignCurrent()
{
if (Interlocked.CompareExchange(ref _current, null, this) == this)
{
CurrentChanged?.Invoke(this, new CurrentActivityChangedEventArgs(null));
}
}
#endregion
#region Instance discovery management
private void NotifyCreatingInstance()
{
IImmutableDictionary<int, BaseActivity> capture, updated;
do
{
capture = _instances;
updated = capture.Add(Id, this);
} while (Interlocked.CompareExchange(ref _instances, updated, capture) != capture);
InstancesChanged?.Invoke(null, ActivitiesCollectionChangedEventArgs.Added(Id, updated));
}
private void NotifyDestroyingInstance(bool isFinalizer)
{
try
{
IImmutableDictionary<int, BaseActivity> capture, updated;
do
{
capture = _instances;
if (!capture.ContainsKey(Id))
{
return;
}
updated = capture.Remove(Id);
} while (Interlocked.CompareExchange(ref _instances, updated, capture) != capture);
DispatchedHandler notify = () =>
{
try
{
InstancesChanged?.Invoke(null, ActivitiesCollectionChangedEventArgs.Removed(Id, updated));
}
catch (Exception e)
{
this.Log().Error("An exception was thrown while notifying instance collection changed.", e);
}
};
if (isFinalizer)
{
CoreDispatcher.Main.RunAsync(CoreDispatcherPriority.Normal, notify);
}
else
{
notify();
}
}
catch (Exception e)
{
this.Log().Error("Failed to remove activity from instances collection.", e);
}
}
#endregion
protected sealed override void Dispose(bool disposing)
{
try
{
base.Dispose(disposing);
if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
{
this.Log().DebugFormat("Disposing {0}", disposing);
}
NotifyDestroyingInstance(isFinalizer: !disposing);
if (disposing)
{
#if !IS_UNO
Performance.Decrement(ActiveBindableActivityCounter);
#endif
}
}
catch (Exception e)
{
this.Log().ErrorFormat("Failed to dispose view", e);
}
}
public override bool DispatchTouchEvent(MotionEvent ev)
{
if (_trace.IsEnabled)
{
if (ev.Action == MotionEventActions.Down)
{
_trace.WriteEvent(TraceProvider.TouchStart);
}
if (ev.Action == MotionEventActions.Up)
{
_trace.WriteEvent(TraceProvider.TouchStop);
}
}
return base.DispatchTouchEvent(ev);
}
public virtual IEnumerable<IDataContextProvider> GetChildrenProviders() =>
new[] { ContentView as IDataContextProvider }
.Trim();
~BaseActivity()
{
this.Log().Error("~BaseActivity()");
#if !IS_UNO
Performance.Decrement(ActiveBindableActivityCounter);
#endif
}
}
}