Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
MainActivity.cs
1using Android.App;
2using Android.Content;
3using Android.Content.PM;
4using Android.Nfc;
5using Android.Nfc.Tech;
6using Android.OS;
7using AndroidX.Core.View;
8using Microsoft.Maui.Controls.PlatformConfiguration.AndroidSpecific;
16using Plugin.Firebase.CloudMessaging;
17using System.Runtime.Versioning;
18using System.Text;
19using System.Text.Json;
20
21namespace NeuroAccessMaui
22{
23 [Activity(Exported = true, Theme = "@style/Maui.SplashTheme", MainLauncher = true, Name = "com.tag.NeuroAccess.MainActivity",
24 ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density | ConfigChanges.Locale,
25 ScreenOrientation = ScreenOrientation.Portrait, LaunchMode = LaunchMode.SingleTop)]
26 [IntentFilter(
27 [
28 NfcAdapter.ActionNdefDiscovered],
29 Categories = [Intent.CategoryDefault], DataMimeType = "*/*")
30 ]
31 [IntentFilter(
32 [
33 Intent.ActionView
34 ],
35 Categories = [Intent.CategoryDefault, Intent.CategoryBrowsable],
36 DataSchemes = ["iotid", "iotdisco", "iotsc", "tagsign", "obinfo", "edaler", "nfeat", "xmpp", "aes256", "neuroaccess"])]
37 [IntentFilter(
38 [
39 nameof(NotificationAction.OpenChat),
40 nameof(NotificationAction.OpenProfile),
41 nameof(NotificationAction.OpenIdentity),
42 nameof(NotificationAction.OpenPresenceRequest),
43 nameof(NotificationAction.OpenSettings)
44 ],
45 Categories = [Intent.CategoryDefault, Intent.CategoryBrowsable])]
46 public class MainActivity : MauiAppCompatActivity
47 {
48 private static NfcAdapter? nfcAdapter = null;
49
50 private void CreateNotificationChannelsIfNeeded()
51 {
52 if (Build.VERSION.SdkInt >= BuildVersionCodes.O && OperatingSystem.IsAndroidVersionAtLeast(26))
53 this.CreateNotificationChannels();
54 }
55
56 [SupportedOSPlatform("android26.0")]
57 private void CreateNotificationChannels()
58 {
59 NotificationChannel MessagesChannel = new("Messages", "Instant Messages", NotificationImportance.High)
60 {
61 Description = "Channel for incoming Instant Message notifications"
62 };
63
64 NotificationChannel PetitionsChannel = new("Petitions", "Petitions sent by other users", NotificationImportance.High)
65 {
66 Description = "Channel for incoming Contract or Identity Peititions, such as Review or Signature Requests"
67 };
68
69 NotificationChannel IdentitiesChannel = new("Identities", "Identity events", NotificationImportance.High)
70 {
71 Description = "Channel for events relating to the digital identity"
72 };
73
74 NotificationChannel ContractsChannel = new("Contracts", "Contract events", NotificationImportance.High)
75 {
76 Description = "Channel for events relating to smart contracts"
77 };
78
79 NotificationChannel EDalerChannel = new("eDaler", "eDaler events", NotificationImportance.High)
80 {
81 Description = "Channel for events relating to the eDaler wallet balance"
82 };
83
84 NotificationChannel TokensChannel = new("Tokens", "Token events", NotificationImportance.High)
85 {
86 Description = "Channel for events relating to Neuro-Feature tokens"
87 };
88
89 NotificationManager? NotificationManager = this.GetSystemService(NotificationService) as NotificationManager;
90 NotificationManager?.CreateNotificationChannels(new List<NotificationChannel>()
91 {
92 MessagesChannel, PetitionsChannel, IdentitiesChannel, ContractsChannel, EDalerChannel, TokensChannel
93 });
94 FirebaseCloudMessagingImplementation.ChannelId = "Messages"; // Default channel if not specified.
95
96 }
97
98 protected override async void OnCreate(Bundle? savedInstanceState)
99 {
100 try
101 {
102 base.OnCreate(savedInstanceState);
103 this.CreateNotificationChannelsIfNeeded();
104 nfcAdapter = NfcAdapter.GetDefaultAdapter(this);
105 await this.HandleIntent(this.Intent);
106 }
107 catch (Exception ex)
108 {
109 StringBuilder msg = new();
110
111 msg.AppendLine("An error occurred in the Android MainActivity.OnPostCreate method.");
112 msg.AppendLine("Exception message:");
113 msg.Append(ex.Message);
114 msg.AppendLine("\n\n");
115 msg.AppendLine("```");
116 msg.AppendLine(ex.StackTrace);
117 msg.AppendLine("```");
118
119 await App.SendAlertAsync(msg.ToString(), "text/plain");
120 }
121
122 App.Current?.On<Microsoft.Maui.Controls.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
123 if (this.Window is null)
124 return;
125 WindowCompat.SetDecorFitsSystemWindows(this.Window, false);
126 if (OperatingSystem.IsAndroidVersionAtLeast(23) && !OperatingSystem.IsAndroidVersionAtLeast(35))
127 {
128 // Optionally, set transparent nav/status bars
129 this.Window.SetStatusBarColor(Android.Graphics.Color.Transparent);
130 this.Window.SetNavigationBarColor(Android.Graphics.Color.Transparent);
131 }
132 }
133
134 protected override void OnResume()
135 {
136 base.OnResume();
137
138 if (nfcAdapter is not null)
139 {
140 Intent Intent = new Intent(this, this.GetType()).AddFlags(ActivityFlags.SingleTop);
141
142 PendingIntentFlags Flags = PendingIntentFlags.UpdateCurrent;
143 if (OperatingSystem.IsAndroidVersionAtLeast(31))
144 {
145 Flags |= PendingIntentFlags.Mutable;
146 }
147
148 PendingIntent? PendingIntent = Android.App.PendingIntent.GetActivity(this, 0, Intent, Flags);
149 nfcAdapter.EnableForegroundDispatch(this, PendingIntent, null, null);
150 }
151
152 this.RemoveAllNotifications();
153 }
154
155 protected override void OnPause()
156 {
157 base.OnPause();
158 nfcAdapter?.DisableForegroundDispatch(this);
159 }
160
161 protected override async void OnNewIntent(Intent? Intent)
162 {
163 base.OnNewIntent(Intent);
164 await this.HandleIntent(Intent, false);
165 }
166
167 private async Task HandleIntent(Intent? intent, bool Defer = true)
168 {
169 if (intent is null)
170 return;
171 try
172 {
173 AppIntent? AppIntent = null;
174
175 // Retrieve the shared intent service.
178 INotificationRenderer NotificationRenderer = ServiceRef.Provider.GetRequiredService<INotificationRenderer>();
179
180 // Handle push tap intent carrying NotificationIntent JSON.
181 if (intent.Extras is not null && intent.Extras.ContainsKey("notificationIntent"))
182 {
183 string? payload = intent.Extras.GetString("notificationIntent");
184 if (!string.IsNullOrEmpty(payload))
185 {
186 try
187 {
188 NotificationIntent? parsed = JsonSerializer.Deserialize<NotificationIntent>(payload);
189 if (parsed is not null)
190 {
191 parsed.Presentation = this.ResolvePresentation(intent.Extras, parsed.Presentation);
192 await NotificationService.AddAsync(parsed, NotificationSource.Push, payload, CancellationToken.None);
193 string id = NotificationService.ComputeId(parsed, NotificationSource.Push);
194 await NotificationService.ConsumeAsync(id, CancellationToken.None);
195 return;
196 }
197 }
198 catch (Exception ex)
199 {
200 ServiceRef.LogService.LogException(ex);
201 }
202 }
203 }
204 // Handle deep link URL intent.
205 else if (intent.Action == Intent.ActionView)
206 {
207 string? Url = intent.Data?.ToString();
208 if (!string.IsNullOrEmpty(Url))
209 {
210 AppIntent = new AppIntent
211 {
213 Data = Url
214 };
215 }
216 }
217 // Handle data-only push when app is background/terminated: render notification.
218 else if (intent.Extras is not null && intent.Extras.ContainsKey("gcm.notification.body"))
219 {
220 string? Body = intent.Extras.GetString("gcm.notification.body");
221 string? Title = intent.Extras.GetString("gcm.notification.title");
222 string Channel = intent.Extras.GetString("channelId") ?? Constants.PushChannels.Messages;
223
224 NotificationIntent Fallback = new()
225 {
226 Title = Title ?? string.Empty,
227 Body = Body,
228 Channel = Channel,
229 Presentation = this.ResolvePresentation(intent.Extras, NotificationPresentation.RenderAndStore)
230 };
231
232 string Raw = intent.Extras.ToString() ?? string.Empty;
233 await NotificationService.AddAsync(Fallback, NotificationSource.Push, Raw, CancellationToken.None);
234 return;
235 }
236 // Handle NFC intents.
237 else if (intent.Action == NfcAdapter.ActionTagDiscovered ||
238 intent.Action == NfcAdapter.ActionNdefDiscovered ||
239 intent.Action == NfcAdapter.ActionTechDiscovered)
240 {
241 Tag? Tag = null;
242 if (OperatingSystem.IsAndroidVersionAtLeast(33))
243 Tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag, Java.Lang.Class.FromType(typeof(Tag))) as Tag;
244 else
245 Tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
246 if (Tag is null)
247 return;
248
249 byte[]? Id = Tag.GetId();
250 if (Id is null)
251 return;
252
253 string[]? TechList = Tag.GetTechList();
254 if (TechList is null)
255 return;
256
257 List<INfcInterface> Interfaces = [];
258
259 foreach (string Tech in TechList)
260 {
261 switch (Tech)
262 {
263 case "android.nfc.tech.IsoDep":
264 IsoDep? IsoDep = IsoDep.Get(Tag);
265 if (IsoDep is not null)
266 Interfaces.Add(new IsoDepInterface(Tag, IsoDep));
267 break;
268
269 case "android.nfc.tech.MifareClassic":
270 MifareClassic? MifareClassic = MifareClassic.Get(Tag);
271 if (MifareClassic is not null)
272 Interfaces.Add(new MifareClassicInterface(Tag, MifareClassic));
273 break;
274
275 case "android.nfc.tech.MifareUltralight":
276 MifareUltralight? MifareUltralight = MifareUltralight.Get(Tag);
277 if (MifareUltralight is not null)
278 Interfaces.Add(new MifareUltralightInterface(Tag, MifareUltralight));
279 break;
280
281 case "android.nfc.tech.Ndef":
282 Ndef? Ndef = Ndef.Get(Tag);
283 if (Ndef is not null)
284 Interfaces.Add(new NdefInterface(Tag, Ndef));
285 break;
286
287 case "android.nfc.tech.NdefFormatable":
288 NdefFormatable? NdefFormatable = NdefFormatable.Get(Tag);
289 if (NdefFormatable is not null)
290 Interfaces.Add(new NdefFormatableInterface(Tag, NdefFormatable));
291 break;
292
293 case "android.nfc.tech.NfcA":
294 NfcA? NfcA = NfcA.Get(Tag);
295 if (NfcA is not null)
296 Interfaces.Add(new NfcAInterface(Tag, NfcA));
297 break;
298
299 case "android.nfc.tech.NfcB":
300 NfcB? NfcB = NfcB.Get(Tag);
301 if (NfcB is not null)
302 Interfaces.Add(new NfcBInterface(Tag, NfcB));
303 break;
304
305 case "android.nfc.tech.NfcBarcode":
306 NfcBarcode? NfcBarcode = NfcBarcode.Get(Tag);
307 if (NfcBarcode is not null)
308 Interfaces.Add(new NfcBarcodeInterface(Tag, NfcBarcode));
309 break;
310
311 case "android.nfc.tech.NfcF":
312 NfcF? NfcF = NfcF.Get(Tag);
313 if (NfcF is not null)
314 Interfaces.Add(new NfcFInterface(Tag, NfcF));
315 break;
316
317 case "android.nfc.tech.NfcV":
318 NfcV? NfcV = NfcV.Get(Tag);
319 if (NfcV is not null)
320 Interfaces.Add(new NfcVInterface(Tag, NfcV));
321 break;
322 }
323 }
324
325 // Create a shared NfcTag instance with the extracted data.
326 NfcTag NfcTag = new(Id, [.. Interfaces]);
327 AppIntent = new()
328 {
330 Payload = NfcTag
331 };
332 }
333
334 if (AppIntent is null)
335 return;
336
337 if (Defer)
339 else
341
342 }
343 catch (Exception Ex)
344 {
345 ServiceRef.LogService.LogException(Ex);
346 }
347 return;
348 }
349
350 private NotificationPresentation ResolvePresentation(Bundle extras, NotificationPresentation current)
351 {
352 if (extras is null)
353 return current;
354
355 if (extras.ContainsKey("silent"))
356 {
357 string? value = extras.GetString("silent");
358 if (this.IsTrue(value))
359 return NotificationPresentation.StoreOnly;
360 }
361
362 if (extras.ContainsKey("delivery.silent"))
363 {
364 string? value = extras.GetString("delivery.silent");
365 if (this.IsTrue(value))
366 return NotificationPresentation.StoreOnly;
367 }
368
369 return current;
370 }
371
372 private bool IsTrue(string? value)
373 {
374 if (string.IsNullOrWhiteSpace(value))
375 return false;
376
377 return value.Equals("1", StringComparison.OrdinalIgnoreCase) ||
378 value.Equals("true", StringComparison.OrdinalIgnoreCase) ||
379 value.Equals("yes", StringComparison.OrdinalIgnoreCase);
380 }
381
382
383 private void RemoveAllNotifications()
384 {
385 NotificationManager? Manager = (NotificationManager?)this.GetSystemService(NotificationService);
386 Manager?.CancelAll();
387 }
388 }
389}
Represents an instance of the Neuro-Access app.
Definition: App.xaml.cs:125
static new? App Current
Gets the current application instance.
Definition: App.xaml.cs:169
Contains intent action constants used for inter-component communication within the app.
Definition: Constants.cs:1060
const string OpenUrl
Action used to open a URL, typically triggered by deep linking.
Definition: Constants.cs:1064
const string NfcTagDiscovered
Action triggered when an NFC tag is discovered.
Definition: Constants.cs:1069
const string Messages
Messages channel
Definition: Constants.cs:739
A set of never changing property constants and helpful values.
Definition: Constants.cs:24
Represents an application intent containing an action, optional data, and an optional payload.
The IntentService class is responsible for handling and processing application intents in a cross‑pla...
void QueueIntent(AppIntent intent)
Queues an intent for later processing.
async Task ProcessIntentAsync(AppIntent intent)
Processes a single intent asynchronously.
Platform-neutral intent describing how to route a notification.
NotificationPresentation Presentation
Gets or sets how the notification should be presented.
Base class that references services in the app.
Definition: ServiceRef.cs:43
static IServiceProvider Provider
The service provider for the app. This is set before the app is started, and will be used to resolve ...
Definition: ServiceRef.cs:48
static ILogService LogService
Log service.
Definition: ServiceRef.cs:214
Defines the contract for a service that handles application intents.
Interface for the redesigned notification service.
Renders local notifications on the platform.
NotificationAction
Actions that can be routed from notifications.
NotificationPresentation
Presentation preference for a notification intent.
NotificationSource
Describes the source producing a notification.