Compare commits

...

4 Commits

Author SHA1 Message Date
Maurice
007ca4ef0f Improvements 2024-06-19 19:24:15 +02:00
Maurice
dceb5b49d8 Added theme 2024-06-19 19:20:50 +02:00
Maurice
4f21ecb859 Added auth 2024-06-19 19:02:44 +02:00
Maurice
94a4ba1e1e Changes 2024-06-19 16:42:19 +02:00
11 changed files with 125 additions and 20 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
.idea/
obj/
bin/
bin/
/.DS_Store

BIN
DemoAndroid/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -1,11 +1,21 @@
using System.Net;
using System.Net.Sockets;
using Android.Content;
using Android.Hardware.Biometrics;
using Android.OS;
using Java.Lang;
namespace DemoAndroid;
[Activity(Label = "WakeOnLanActivity")]
[Activity(Label = "@string/app_name", MainLauncher = true, Theme = "@style/Default")]
public class WakeOnLanActivity : Activity
{
private const int BiometricStrong = 0x0000000f;
private const int BiometricWeak = 0x000000ff;
private const int DeviceCredential = 0x00008000;
private bool _authenticated = false;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
@ -16,25 +26,51 @@ public class WakeOnLanActivity : Activity
var button = FindViewById<Button>(Resource.Id.btnWakeOnLan);
button.Click += (sender, args) =>
{
WakePc();
OnlyAuthenticated(WakePc);
};
}
private void OnlyAuthenticated(Action action)
{
if (!_authenticated)
{
var callback = new BiometricCallback(this, () =>
{
_authenticated = true;
action();
});
var prompt = new BiometricPrompt.Builder(this)
.SetNegativeButton("Annuleren", MainExecutor, callback)
.SetTitle("Bewijs jezelf met je vingerafdruk")
.SetSubtitle("We willen zeker weten dat je niet Colinde bent")
.SetAllowedAuthenticators(BiometricStrong)
.Build();
var cancellation = new CancellationSignal();
prompt.Authenticate(cancellation, MainExecutor, callback);
return;
}
action();
}
private void WakePc()
{
byte[] macAddress = { 0x2c, 0x4d, 0x54, 0x4d, 0x10, 0x0f };
byte[] magicPacket = new byte[102];
byte[] macAddress = [0x2c, 0x4d, 0x54, 0x4d, 0x10, 0x0f];
var magicPacket = new byte[102];
// Fill first 6 bytes with 0xFF
for (int i = 0; i < 6; i++)
for (var i = 0; i < 6; i++)
{
magicPacket[i] = 0xFF;
}
// Repeat MAC address 16 times
for (int i = 1; i <= 16; i++)
for (var i = 1; i <= 16; i++)
{
for (int j = 0; j < 6; j++)
for (var j = 0; j < 6; j++)
{
magicPacket[i * 6 + j] = macAddress[j];
}
@ -44,10 +80,49 @@ public class WakeOnLanActivity : Activity
client.EnableBroadcast = true;
var endpoint = new IPEndPoint(IPAddress.Broadcast, 9); // 255.255.255.255 port 9
for (int i = 0; i < 5; i++)
for (var i = 0; i < 5; i++)
{
// Try 5 times
client.Send(magicPacket, magicPacket.Length, endpoint);
}
Toast.MakeText(this, "Computer started!", ToastLength.Long)!.Show();
}
}
/// <summary>
/// Biometric authentication callbacks
/// https://developer.android.com/identity/sign-in/biometric-auth#java
/// </summary>
class BiometricCallback : BiometricPrompt.AuthenticationCallback, IDialogInterfaceOnClickListener
{
private Context _context;
private readonly Action _onSuccess;
public BiometricCallback(Context context, Action onSuccess)
{
_context = context;
_onSuccess = onSuccess;
}
public override void OnAuthenticationError(BiometricErrorCode errorCode, ICharSequence? errString)
{
Toast.MakeText(_context, $"Authenticatie mislukt: {errorCode}, {errString?.ToString()}", ToastLength.Long)!.Show();
}
public override void OnAuthenticationSucceeded(BiometricPrompt.AuthenticationResult? result)
{
Toast.MakeText(_context, "Authentication succeeded!", ToastLength.Short)!.Show();
_onSuccess();
}
public override void OnAuthenticationFailed()
{
Toast.MakeText(_context, "Authenticatie mislukt!", ToastLength.Long)!.Show();
}
public void OnClick(IDialogInterface? dialog, int which)
{
Toast.MakeText(_context, "Geannuleerd!", ToastLength.Long)!.Show();
}
}

View File

@ -3,4 +3,6 @@
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:label="@string/app_name" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true">
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
</manifest>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion>30</SupportedOSPlatformVersion>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
@ -12,11 +12,10 @@
<!-- With AOT, our app is crashing in Release mode -->
<RunAOTCompilation>False</RunAOTCompilation>
<PublishAot>False</PublishAot>
<TargetFrameworkVersion>v13.0</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QRCoder-ImageSharp" Version="0.10.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Activities\" />
</ItemGroup>
</Project>

View File

@ -4,7 +4,7 @@ using QRCoder; // QRCoder-ImageSharp else it crashes
namespace DemoAndroid;
[Activity(Label = "@string/app_name", MainLauncher = true)]
[Activity(Label = "@string/app_name", MainLauncher = false)]
public class MainActivity : Activity
{
private string _text = "";

15
DemoAndroid/README.md Normal file
View File

@ -0,0 +1,15 @@
# Android Native C# readme
1. AOT makes release versions crash sometimes, so it is disabled
2. Project created with
```bash
dotnet new android
```
3. New activities can be created with
```bash
dotnet new android-activity -n MyNewActivity
```
4. Avoid NuGet packages that are not built for non-Windows environments (e.g. depend on System.Drawing)
If the app crashes directly in Release, before reverting all your changes try to clean /bin and /obj
Also, if you reverted some changes, clean /bin and /obj again before thinking it still doesn't work

View File

@ -2,18 +2,19 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:layout_margin="5pt">
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start PC by tapping button below" />
android:text="Start de computer met Wake-On-Lan door op de knop hieronder te klikken" />
<Button android:id="@+id/btnWakeOnLan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start PC"
android:text="Start de computer"
android:textColor="@color/white"
android:background="@color/blue"
android:height="15pt"
android:background="@color/green"
android:height="20pt"
android:layout_margin="10pt"/>
</LinearLayout>

View File

@ -2,4 +2,5 @@
<resources>
<color name="blue">#4287f5</color>
<color name="white">#FFFFFF</color>
<color name="green">#2abf39</color>
</resources>

View File

@ -1,4 +1,4 @@
<resources>
<string name="app_name">DemoAndroid</string>
<string name="app_name">Goofjes</string>
<string name="app_text">Hello, Android!</string>
</resources>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Default" parent="@android:style/Theme.Material.Light.DarkActionBar">
</style>
<style name="NoActionBar" parent="@android:style/Theme.Material.Light.DarkActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
</resources>