How would i make this repeat? - android

I am trying to make an alarm notification and I want it to repeat when this 2 radio buttons are active.
I have this code :
private void Button_Clicked(object sender, EventArgs e) {
if (Radio_Msg.IsChecked) {
CrossToastPopUp.Current.ShowToastWarning("Alarme");
}
if (Radio_Notif.IsChecked) {
CrossLocalNotifications.Current.Show("Miguel", "Módulo 19 – Tecnologias de Acesso a Base de Dados");
}
if (Radio_Msg.IsChecked && RadioRepetir == true) {
CrossToastPopUp.Current.ShowToastMessage("Tesddddte");
Thread.Sleep(500);
CrossToastPopUp.Current.ShowToastMessage("Teste");
}
}
But it doesn't repeat it, it only prints one notification out.

if(Radio_Msg.IsChecked && RadioRepetir == true)
{
var minutes = TimeSpan.FromMinutes(0.2);
Device.StartTimer(minutes, () => {
CrossToastPopUp.Current.ShowToastWarning("Alarme");
return true;
});

Related

Xamarin why it hangs on permissions enabling?

I done this according to Xamarin documentation, just copy-pasted a code.
So, in App.xaml.cs I have a code like this:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
protected override void OnStart()
{
if (!CheckPermisions())
{
AbortApp(3, "Missing required permissions!");
return ;
}
}
//[...]
public bool CheckPermisions()
{
Task<bool> v = performCheckPermisions();
if (v.Result)
initAppFolders();
return v.Result;
}
protected async Task<bool> performCheckPermisions()
{
// storage read
PermissionStatus status = await Xamarin.Essentials.Permissions.CheckStatusAsync<Permissions.StorageRead>();
if (status == PermissionStatus.Denied)
{
this.Context.ToLogger(EAppLogLevel.Warning, string.Format(" ! StorageRead: requesting..."));
status = await Permissions.RequestAsync<Permissions.StorageRead>();
}
if (status == PermissionStatus.Denied)
return false;
// storage write
status = await Xamarin.Essentials.Permissions.CheckStatusAsync<Permissions.StorageWrite>();
if (status == PermissionStatus.Denied)
{
this.Context.ToLogger(EAppLogLevel.Warning, string.Format(" ! StorageWrite: requesting..."));
status = await Permissions.RequestAsync<Permissions.StorageWrite>();
}
if (status == PermissionStatus.Denied)
return false;
return true; // Task.FromResult(true);
}
The problem is - when application started 1st time, so when the OS asks user for permissions it always hangs! :-(
And I do not understand - why?!
How to resolve this problem with hanging on 1st app run?
I tried to debug it but it never returns from await Permissions.RequestAsync<...>() back into debugger! :-
Of course - on OS request I clicked [Allow] in a UI prompt.
Unfortunately, I'm not sure - why it is not returning, it might be bug in VS2019 debugger or it might be bug in Xamarin... or maybe I'm doing something wrong.
Could you please advice?
Please note: I need exactly the blocking/synchronous call to permissions request! Application must stop and confirm if permissions granted. Without permissions - it must not even try to run.
Note: VS 2019 (16.6.5); Xamarin.Forms 4.7.0.1142; Xamarin.Essentials 1.5.3.2 - so, it seems all the latest.
Thanks.
PS.
Also I tried following variants:
Attempt# 1
Task<bool> tsk = performCheckPermisions();
bool result = false;
if (tsk.IsCompleted)
{
this.Context.ToLogger(EAppLogLevel.Info, string.Format(" . CheckPermisions: task completed without waiting..."));
result = tsk.Result;
}
else
{
TaskAwaiter<bool> aw = tsk.GetAwaiter();
int counter = 0;
while (!aw.IsCompleted)
{
Thread.Sleep(330);
counter++;
if ((counter % 10) == 0)
this.Context.ToLogger(EAppLogLevel.Info, string.Format(" . CheckPermisions: still waiting (#{0})...", counter));
if (counter > 100)
{
AbortApp(99, "Permissions were not comfirmed!");
return false;
}
}
result = aw.GetResult();
}
It simply hang because nor tsk.IsCompleted, nor aw.IsCompleted never became true despite user clicks to [Allow] button.
Attempt# 2
var task = Task.Run(async () => await performCheckPermisions());
if (task.IsFaulted && task.Exception != null)
{
throw task.Exception;
}
bool result = task.Result;
this.Context.ToLogger(EAppLogLevel.Info, string.Format(" ? CheckPermisions: {0}", result));
It reported System.AggregateException exception: Message=One or more errors occurred. (Permission request must be invoked on main thread.); Source=mscorlib.
Attempt# 3
bool result = false;
this.isCompleted = false;
MainThread.BeginInvokeOnMainThread(
async () => {
result = await performCheckPermisions();
this.isCompleted = true;
}
);
int counter = 0;
while (!this.isCompleted)
{
Thread.Sleep(330);
counter++;
if ((counter % 10) == 0)
this.Context.ToLogger(EAppLogLevel.Info, string.Format(" . CheckPermisions: still waiting (#{0})...", counter));
if (counter > 100)
{
AbortApp(99, "Permissions were not comfirmed within specified timeout!");
return false;
}
}
It simply hang. It seems there is bug in Xamarin - the await Permissions.RequestAsync<>() call never return back to application!
Below is the edited code. If you saw an earlier version then you saw it had problems. First entry so am new at this. *
I tried many things to get the permissions but it always hung the App, even with the awaits.
I wanted to put the permission requests as close to where the user required them (As recommended) and not abort the App. This is what I finally came up with:
Creating a permission interface in the Xamarin Forms project
Creating an Android implementation of the permissions in the Xamarin Forms Android project
Registered permission as dependency service in the Android Activity before loading the Forms App
In my WIFI Content page I created an async method that checks permission by calling the registered Dependency service
When I click on WIFI page scan button, it calls the async method to see if the user needs to give permission before continuing
Works like a charm.
The only caveat is that if the user selects 'Don't ask again' he will have to set location services manually. Not sure how I can tell the user since the permissions always only return Denied status. He will get a dialog informing him of insufficient permissions but no OS dialog allowing him to request permissions (Duh, because he said that that he did not want to see them)
The permissions Interface in the Xamarin Forms project
public interface ILocationWhileInUsePermission {
Task<PermissionStatus> CheckStatusAsync();
Task<PermissionStatus> RequestAsync();
}
Implementation on Xamarin Forms Android side
public class LocationWhileInUsePermission : Xamarin.Essentials.Permissions.BasePlatformPermission, ILocationWhileInUsePermission {
public override (string androidPermission, bool isRuntime)[]
RequiredPermissions => new List<(string androidPermission, bool isRuntime)> {
(Android.Manifest.Permission.AccessFineLocation, true),
(Android.Manifest.Permission.AccessCoarseLocation, true),
(Android.Manifest.Permission.AccessWifiState, true),
(Android.Manifest.Permission.ChangeWifiState, true)
}.ToArray();
}
Register in the Activity.cs OnCreate before load of the App
DependencyService.Register<ILocationWhileInUsePermission, LocationWhileInUsePermission>();
LoadApplication(new App(DI.Wrapper));
In the Wifi Page create functions to invoke permissions from DependencyService and to set results
private bool permissionsGranted = false;
private async Task SetAreGranted(bool granted) {
await Task.Run(() => this.permissionsGranted = granted);
}
public async Task<bool> GetIsGranted() {
return await Task<bool>.Run(() => { return this.permissionsGranted; });
}
public async Task<bool> ChkWifiPermissions() {
try {
await this.SetAreGranted(false);
var wifiPermissions =
DependencyService.Get<ILocationWhileInUsePermission>();
var status = await wifiPermissions.CheckStatusAsync();
if (status != PermissionStatus.Granted) {
status = await wifiPermissions.RequestAsync();
if (status != PermissionStatus.Granted) {
return await this.GetIsGranted();
}
}
await this.SetAreGranted(true);
}
catch (Exception) {
return await this.GetIsGranted();
}
return await this.GetIsGranted();
}
On my WIFI Content Page, on the button click event I call the async method
private void btnDiscover_Clicked(object sender, EventArgs e) {
Device.BeginInvokeOnMainThread(async () => {
if (await this.ChkWifiPermissions()) {
this.btnSelect.IsVisible = false;
this.ResetWifiList(new List<WifiNetworkInfo>());
this.activity.IsRunning = true;
App.Wrapper.WifiDiscoverAsync();
}
else {
this.OnErr("Insufficient permissions to continue");
}
});
}
Just to add a variance to my WIFI permissions check on WIFI scan button, here is a variance that aborts on App start. It works but I prefer the one that requests closer to the usage of the permission.
This works and never hangs the App. Still the problem if the user has requested not to be asked again.
Start by declaring service interfaces in the Xamarin Forms project to close the App, and another to check and request permissions
public interface ICloseApplication {
void CloseApp();
}
public interface ILocationWhileInUsePermission {
Task<PermissionStatus> CheckStatusAsync();
Task<PermissionStatus> RequestAsync();
}
Then add Android OS implmentations in the Xamarin Forms Android project
public class AndroidCloseApp : ICloseApplication {
public void CloseApp() {
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
}
public class LocationWhileInUsePermission : Xamarin.Essentials.Permissions.BasePlatformPermission, ILocationWhileInUsePermission {
public override (string androidPermission, bool isRuntime)[]
RequiredPermissions => new List<(string androidPermission, bool isRuntime)> {
(Android.Manifest.Permission.AccessFineLocation, true),
(Android.Manifest.Permission.AccessCoarseLocation, true),
(Android.Manifest.Permission.AccessWifiState, true),
(Android.Manifest.Permission.ChangeWifiState, true)
}.ToArray();
}
Register the Services in the Xamarin Forms Android project MainActivity.OnCreate(). BTW, the DI.Wrapper has the results from my dependency injector, with common and OS specific code
DependencyService.Register<ILocationWhileInUsePermission, LocationWhileInUsePermission>();
DependencyService.Register<ICloseApplication, AndroidCloseApp>();
LoadApplication(new App(DI.Wrapper));
Then in the Xamarin Forms project, in the App.OnStart() override method call an async method to request permissions and abort if necessary
protected override void OnStart() {
// This will abort the app at the start if the WIFI permissions are not given
Device.BeginInvokeOnMainThread(async () => {
if (!await this.CheckPermissions()) {
ICloseApplication closeApp = DependencyService.Get<ICloseApplication>();
await Application.Current.MainPage.DisplayAlert(
App.GetText(MsgCode.Error),
"Insufficient permissions",
App.GetText(MsgCode.Ok));
closeApp.CloseApp();
}
});
}
private async Task<bool> CheckPermissions() {
ILocationWhileInUsePermission wifiPermissions =
DependencyService.Get<ILocationWhileInUsePermission>();
PermissionStatus status = await wifiPermissions.CheckStatusAsync();
if (status != PermissionStatus.Granted) {
status = await wifiPermissions.RequestAsync();
}
return status == PermissionStatus.Granted;
}
As Cheesebaron mentioned, you always want to use await when dealing with a Task. You can modify your example like so:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
protected override async void OnStart()
{
bool result = await CheckPermisions()
if (!result)
{
AbortApp(3, "Missing required permissions!");
return ;
}
}
//[...]
public async Task<bool> CheckPermisions()
{
bool v = await performCheckPermisions();
if (v)
initAppFolders();
return v;
}
protected async Task<bool> performCheckPermisions()
{
// storage read
PermissionStatus status = await Xamarin.Essentials.Permissions.CheckStatusAsync<Permissions.StorageRead>();
if (status == PermissionStatus.Denied)
{
this.Context.ToLogger(EAppLogLevel.Warning, string.Format(" ! StorageRead: requesting..."));
status = await Permissions.RequestAsync<Permissions.StorageRead>();
}
if (status == PermissionStatus.Denied)
return false;
// storage write
status = await Xamarin.Essentials.Permissions.CheckStatusAsync<Permissions.StorageWrite>();
if (status == PermissionStatus.Denied)
{
this.Context.ToLogger(EAppLogLevel.Warning, string.Format(" ! StorageWrite: requesting..."));
status = await Permissions.RequestAsync<Permissions.StorageWrite>();
}
if (status == PermissionStatus.Denied)
return false;
return true; // Task.FromResult(true);
}
}

Flutter Blue Setting Notifications

I've been using flutter Blue for some now and I'm stuck on the following:
I'm using the example App I downloaded on https://github.com/pauldemarco/flutter_blue, through here the basic idea is that as soon as I connect to my bluetooth device it starts checking if the service "FFE0" exists and then the characteristic "FFE1".
This Characteristic spits out random strings I need for my project.
Image of screen with characteristic open
Through the screen I can see the above is true I just need to somehow automatically set notifications for the characteristic as soon as it connects to the bluetooth device.
This is some current code i'm testing out in the _Connect Function.
_connect(BluetoothDevice d) async {
device = d;
// Connect to device
deviceConnection = _flutterBlue
.connect(device, timeout: const Duration(seconds: 4))
.listen(
null,
onDone: _disconnect,
);
// Update the connection state immediately
device.state.then((s) {
setState(() {
deviceState = s;
});
});
// Subscribe to connection changes
deviceStateSubscription = device.onStateChanged().listen((s) {
setState(() {
deviceState = s;
});
if (s == BluetoothDeviceState.connected) {
device.discoverServices().then((service) {
service.forEach((_service){
var characteristics = _service.characteristics;
_service.characteristics.map((c) {
print(c);
});
for(BluetoothCharacteristic _characteristic in characteristics) {
device.readCharacteristic(_characteristic).then((_value){
print(_value);
if (_value.contains("FFE0")) {
print("Found!!");
// do something
}
});
}
});
setState(() {
services = service;
});
_getServices();
});
}
});
}
I maybe someone has a suggestion on how to approach my problem.
Robin
I found https://github.com/Sensirion/smart-gadget-flutter/tree/master/lib and I was able to fix my problem using the following code:
for(BluetoothService service in services) {
for(BluetoothCharacteristic c in service.characteristics) {
if(c.uuid == new Guid("0000ffe1-0000-1000-8000-00805f9b34fb")) {
_setNotification(c);
} else {
print("Nope");
}
}
}
This was added in the _connect function.
_connect(BluetoothDevice d) async {
device = d;
// Connect to device
deviceConnection = _flutterBlue
.connect(device, timeout: const Duration(seconds: 4))
.listen(
null,
onDone: _disconnect,
);
// Update the connection state immediately
device.state.then((s) {
setState(() {
deviceState = s;
});
});
// Subscribe to connection changes
deviceStateSubscription = device.onStateChanged().listen((s) {
setState(() {
deviceState = s;
});
if (s == BluetoothDeviceState.connected) {
device.discoverServices().then((s) {
services = s;
for(BluetoothService service in services) {
for(BluetoothCharacteristic c in service.characteristics) {
if(c.uuid == new Guid("0000ffe1-0000-1000-8000-00805f9b34fb")) {
_setNotification(c);
} else {
print("Nope");
}
}
}
setState(() {
services = s;
});
_getServices();
});
}
});
}

Sonarqube showing as bug on the return type in xamarin android

I am running sonarqube and fixing the errors. Actually most of the async methods which we used in our project we are returning void. But in the sonar report it is throwing error that it should return Task instead of void. When I changed the void to Task and executed sonar it is throwing error as "the method has the wron return type.
Can anybody please help me on this.
private async void OnNextBtnClick()
{
try
{
if (condition)
{
await Task.Delay(100);
_loadingService.ShowProgressBar();
if (_connectionService.CheckOnline())
{
fun();
CreatedTransactionRequest request =
new CreatedTransactionRequest
{
--------------------------
};
var response = await _orderDataService.GetCreatedTransactionDetails(request).ConfigureAwait(false);
var navFlag = HandleNavigationBasedOnResponse(response);
if (navFlag == Convert.ToInt16(NavigationType.CreateDropOff))
{
ShowScheduleDropOneScreen();
_loadingService.HideProgressBar();
}
else if (navFlag == Convert.ToInt16(NavigationType.DropOffDialog))
{
ShowDropoffDialogScreen();
_loadingService.HideProgressBar();
}
else if (navFlag == Convert.ToInt16(NavigationType.TransactionDialog))
{
ShowTransactionDialogScreen();
_loadingService.HideProgressBar();
}
}
else
{
_loadingService.HideProgressBar();
await _dialogService.ShowAlertAsync(TextSource.GetText("NetworkError"), TextSource.GetText("Error"),
TextSource.GetText("ok"),
Constants.AlertType.Error).ConfigureAwait(false);
}
}
else
{
----------------------------------
}
}
catch (Exception ex)
{
_loadingService.HideProgressBar();
await _exceptionHandlerService.HandleErrorAsync(ex).ConfigureAwait(false);
}
}
Well from my understanding of the situation you are trying to convert a void method to Task it's very easy without any change of code
Something like this :
private async Task yourMehtod()
{
await Task.Factory.StartNew(async() => { await yourVoidMethod(); });
}

Why the the httpInterceptor got rejected when the App starts even when there is network?

I'm using the following code to show a message when there is no network. It works well when testing the app in airplane mode. However, it always shows the popup even when there is network when the app code start (rejection.status === 0). How to workaround it?
.config(function($provide, $httpProvider) {
$provide.factory('httpInterceptor', function($q, $injector) {
return {
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
var interactiveService = $injector.get('interactiveService');
if (rejection.status === 0 || rejection.status === -1) {
interactiveService.showPopup('The internet is disconnected on your device.' + rejection.status);
}
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('httpInterceptor');
})
If it helps try this
.config(function($provide, $httpProvider) {
$provide.factory('httpInterceptor', function($q, $injector) {
return {
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
var interactiveService = $injector.get('interactiveService');
/************** New code starts*******/
var networkState = navigator.connection.type;
if(networkState === Connection.NONE){
interactiveService.showPopup('The internet is disconnected on your device.' + rejection.status);
}
/************** New code ends*******/
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('httpInterceptor');
})

Unity Master Server Vs Simple Client Server

I have written two programs and i want both of these to run on my android device which are on the same network but one which is simple client server program it will run on both device and connection will be made...But Unity Master Server will not run fine and not able to connect two android wifi device which are on the same network and this program will run fine on localhost.
Here is simple client server code..This code run fine
var object:Transform;
static var Isconnected:boolean=false;
//172.16.11.4
function Start()
{
Application.runInBackground = true;
Debug.Log("run in back groud");
}
function Update()
{
if(Isconnected)
var temp:Transform;
temp=Instantiate(object,transform.position, transform.rotation);
}
function OnGUI()
{
if(Network.peerType==NetworkPeerType.Disconnected)
{
if(GUILayout.Button(" Initlized server"))
{
var useNat = !Network.HavePublicAddress();
Network.InitializeServer(32,25001,useNat);
Debug.Log("Server has been Initlized");
}
}
if(GUILayout.Button("connect to server"))
{
Network.Connect("172.16.11.4",25001);
}
}
function OnConnectedToServer() {
Debug.Log("Connected to server");
Isconnected=true;
// Send local player name to server ...
}
But this code will not run on wifi...WHile this code run on localhost if we give the ip 127.0.0.1
#pragma strict
private var rotAngle : float = 0;
private var pivotPoint : Vector2;
var Gamename:String="MyGame";
var refreshing:boolean=false;
private var hostdata:HostData[];
function Start () {
}
function Update () {
var farword=Input.GetKey("up");
if(farword==true)
{
//animation.Play("ArmatureAction");
}
transform.Translate(0,0,Input.GetAxis("Vertical"));
transform.Rotate(0,Input.GetAxis("Horizontal"),0);
if(refreshing)
{
if(MasterServer.PollHostList().Length>0)
{
refreshing=false;
hostdata=MasterServer.PollHostList();
Debug.Log(MasterServer.PollHostList().Length);
}
}
}
function startServer()
{
Network.InitializeServer(32,25001,!Network.HavePublicAddress);
MasterServer.RegisterHost(Gamename,"THis is tutorial","THis is tutorial game");
}
function OnServerInitialized()
{
Debug.Log("Sever is initlized");
}
function OnMasterServerEvent(mgs:MasterServerEvent)
{
if(mgs==MasterServerEvent.RegistrationSucceeded)
{
Debug.Log("Register server");
}
}
function refreshHostList(){
MasterServer.RequestHostList(Gamename);
refreshing=true;
}
function OnGUI()
{
if((!Network.isClient && !Network.isServer))
{
if(GUI.Button(Rect(100,100,100,100),"Start Sever"))
{
Debug.Log("Start Server");
startServer();
}
if(GUI.Button(Rect(100,220,100,100),"Refresg Hosts"))
{
Debug.Log("Refresh HOsts");
refreshHostList();
}
if(hostdata)
{
for(var i:int=0;i<hostdata.length;i++)
{
if(GUI.Button(Rect(230,100,100,100),hostdata[i].gameName))
{
Network.Connect("172.16.11.4",25001);
}
}
}
}
if(GUI.Button(Rect(300,300,100,100),"back"))
{
transform.Translate(9,0,0);
}
if(GUI.Button(Rect(300,400,100,100),"farword"))
{
transform.Translate(-9,0,0);
}
}
Any help
I think in second code
if(hostdata)
{
for(var i:int=0;i<hostdata.length;i++)
{
if(GUI.Button(Rect(230,100,100,100),hostdata[i].gameName))
{
Network.Connect("172.16.11.4",25001);
}
}
need to change
if(hostdata)
{
for(var i:int=0;i<hostdata.length;i++)
{
if(GUI.Button(Rect(230,100,100,100),hostdata[i].gameName))
{
Network.Connect(hostdata[i]); //Or Network.Connect( hostdata[i].ip[ 0 ], hostdata[i].port );
}
}
And also your buttons will overlay themselves. (if more than 1 server initialized and found). You need to create Rect with dynamic start height value. Like:
if(hostdata)
{
var y = 100; // or other start y position like 0
for(var i:int=0;i<hostdata.length;i++)
{
if(GUI.Button(Rect(230,y,100,100),hostdata[i].gameName))
{
Network.Connect(hostdata[i]); //Or Network.Connect( hostdata[i].ip[ 0 ], hostdata[i].port );
}
y+=100+ 5 //Some padding.
}
if any problems occurs like can not connect the server keep in mind NAT punchthrough generally cause problems.

Categories

Resources