How to develop auto logout using Xamarin app - c#

I have to add functionality on the App.xaml.cs to get this to work. I added functionality on OnStart but now it logs me out of the app over and over again intermittently. What do I need to do to get it to stop doing this based on my code below. Or is there a problem at all with my code. Here is my latest code:
namespace MyApp
{
public partial class App : Application
{
DateTime _sessionStart;
public App()
{
InitializeComponent();
DatabaseManager = new DatabaseManager(new DatabaseService());
HttpManager = new HttpManager(new HTTPService());
MainPage = new NavigationPage(new LoginPage());
}
protected override void OnStart()
{
// Handle when your app starts
_sessionStart = DateTime.Now;
Device.StartTimer(TimeSpan.FromSeconds(60), () =>
{
// Check if 24 hours has elapsed
if (DateTime.Now > _sessionStart.AddHours(24))
{
//logout
MainPage = new NavigationPage(new LoginPage());
}
return true; // True = Repeat again, False = Stop the timer
});
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}

Try tracking the idle time (time without touches in the app) by registering a custom application on Main. See example below
Set TimeoutInSeconds value to your desired interval (ex 24 hours)
public class Application
{
// This is the main entry point of the application.
static void Main (string[] args)
{
UIApplication.Main (args, "MYCUSTOMAPP", "AppDelegate");
}
}
[Register ("MYCUSTOMAPP")]
public class MYCUSTOMAPP : UIApplication
{
const int TimeoutInSeconds = 1800; // 30 minutes
NSTimer idleTimer;
public override void SendEvent (UIEvent uievent)
{
base.SendEvent (uievent);
if (idleTimer == null)
ResetTimer ();
var allTouches = uievent.AllTouches;
if (allTouches != null && allTouches.Count > 0 && ((UITouch)allTouches.First ()).Phase == UITouchPhase.Began)
ResetTimer ();
}
void ResetTimer ()
{
if (idleTimer != null)
idleTimer.Invalidate ();
idleTimer = NSTimer.CreateScheduledTimer (new TimeSpan (0, 0, TimeoutInSeconds), (t) => TimerExceeded());
}
void TimerExceeded ()
{
NSNotificationCenter.DefaultCenter.PostNotificationName ("TimeoutNotification", null);
}
}
Add an observer to you view controller to log them out
public override void ViewDidLoad()
{
base.ViewDidLoad();
NSNotificationCenter.DefaultCenter.AddObserver(new NSString("TimeoutNotification"), handleInactivityNotification);
}
public void handleInactivityNotification(NSNotification notification)
{
//Return to login page (Root view controller)
this.NavigationController.PopToRootViewController(true);
}

Related

Is it possible to inject services inside a Timer in ASP.NET Core?

I am currently developing a multiplayer web game with timer using ASP.NET Core. For real time communication I am using SignalR. Everythning up to the moment had been working just fine.
The way I implemented the timer functionality was the following: I created a static dictionary where the key is the Id of the game and the value is the timer corresponding to the given game. Then I exposed public methods for managing the state of the dictionary:
public class TimerManager
{
private static readonly Dictionary<string, GameTimer> gameTimersByGameIds = new();
public void AttachTimerToGameState(GameTimer timer, string gameId)
{
if (!gameTimersByGameIds.ContainsKey(gameId))
{
gameTimersByGameIds.Add(gameId, timer);
return;
}
gameTimersByGameIds[gameId] = timer;
}
public GameTimer? GetTimer(string gameId)
{
if (!gameTimersByGameIds.ContainsKey(gameId))
{
return null;
}
return gameTimersByGameIds[gameId];
}
public GameTimer CreateTimer(GameState gameState)
{
if (gameState.RemainingSecondsByUserNames.Count == 0)
{
return ActivatorUtilities.CreateInstance<StandardTimer>(_serviceProvider, gameState);
}
else
{
return ActivatorUtilities.CreateInstance<ChessTimer>(_serviceProvider, gameState, _gamesService);
}
}
}
I created my own base GameTimer class which encapsulates a System.Timers.Timer inside of it:
public abstract class GameTimer
{
protected readonly System.Timers.Timer _timer = new();
public virtual void Reset()
{
_timer.AutoReset = true;
_timer.Interval = 1_000;
}
public virtual void Start()
{
_timer.Start();
}
public virtual void Dispose()
{
_timer.Dispose();
}
}
Then I inherited from the abstract GameTimer class to create different types of timers.
public class StandardTimer : GameTimer
public class ChessTimer : GameTimer
The problem is inside of the ChessTimer class:
public class ChessTimer : GameTimer
{
private readonly GameState _gameState;
private readonly IGameService _gameService;
private readonly IHubContext<GameHub, IGameClient> _hubContext;
private readonly IMatchmakingService _matchmakingService;
private readonly IGamesService _gamesService;
public ChessTimer(
GameState gameState,
IGamesService gamesService,
IGameService gameService,
IHubContext<GameHub, IGameClient> hubContext,
IMatchmakingService matchmakingService)
{
_gameState = gameState;
_gameService = gameService;
_hubContext = hubContext;
_matchmakingService = matchmakingService;
_gamesService = gamesService;
Reset();
_timer.Elapsed += async (sender, args) => await OnTimedEvent(sender, args);
}
public int SecondsRemaining { get; private set; }
public override void Reset()
{
string currentPlayerName = _gameState.CurrentTeam.CurrentPlayer.UserName;
SecondsRemaining = _gameState.RemainingSecondsByUserNames[currentPlayerName];
base.Reset();
}
private async Task OnTimedEvent(object? sender, ElapsedEventArgs args)
{
if (SecondsRemaining >= 0)
{
string currentPlayerUserName = _gameState.CurrentTeam.CurrentPlayer.UserName;
_gameState.RemainingSecondsByUserNames[currentPlayerUserName] = SecondsRemaining;
int minutes = SecondsRemaining / 60;
int seconds = SecondsRemaining % 60;
var viewModel = new UpdateGameTimerViewModel
{
Minutes = minutes,
Seconds = seconds,
};
foreach (Player player in _gameState.Players)
{
if (player.ConnectionId == null)
{
continue;
}
await _hubContext.Clients
.Client(player.ConnectionId)
.UpdateGameTimer(viewModel);
}
SecondsRemaining--;
return;
}
if (_gameState.RemainingSecondsByUserNames.All(x => x.Value <= 0))
{
_gameState.EndGame();
}
else
{
_gameState.NextTeam();
}
foreach (Player player in _gameState.Players)
{
_gameService.FillPlayerTiles(_gameState, player);
}
foreach (Player player in _gameState.Players)
{
if (player.ConnectionId == null)
{
continue;
}
var viewModel = _gameService.MapFromGameState(_gameState, player.UserName);
await _hubContext.Clients
.Client(player.ConnectionId)
.UpdateGameState(viewModel);
if (_gameState.IsGameOver)
{
_matchmakingService.RemoveUserFromGame(player.UserName);
await _hubContext.Groups
.RemoveFromGroupAsync(
player.ConnectionId, _gameState.GameId);
}
}
if (_gameState.IsGameOver)
{
_matchmakingService.RemoveGameState(_gameState.GameId);
await _gamesService!.SaveGameAsync(new SaveGameInputModel
{
GameId = _gameState.GameId,
Players = _gameState.Players
});
Dispose();
}
Reset();
}
}
Basically the way my OnTimedEvent method works is that it executes every second. Then checks whether the time of all players has run out. If it hasn't it updates the state of the game, otherwise is ends the game. After everything else is done, I try to save the game inside my database in order to enable the users to see summary about their played games. I am using a class called GamesService for this task. It uses UserManager internally to perform some work with the Users in the database.
if (_gameState.IsGameOver)
{
_matchmakingService.RemoveGameState(_gameState.GameId);
await _gamesService!.SaveGameAsync(new SaveGameInputModel
{
GameId = _gameState.GameId,
Players = _gameState.Players
});
Dispose();
}
Reset();
The problem is that when the game ends and the above code is executed it produces the following exception:
Unhandled exception. Unhandled exception. System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'UserManager`1'.
at Microsoft.AspNetCore.Identity.UserManager`1.ThrowIfDisposed()
at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)
at SuperScrabble.Services.Data.Users.UsersService.GetByUserNameAsync(String userName) in C:\Users\georg\Source\Github\SuperScrabble\src\Server\Services\SuperScrabble.Services.Data\Users\UsersService.cs:line 64
at SuperScrabble.Services.Data.Games.GamesService.SaveGameAsync(SaveGameInputModel input) in C:\Users\georg\Source\Github\SuperScrabble\src\Server\Services\SuperScrabble.Services.Data\Games\GamesService.cs:line 52
at SuperScrabble.WebApi.Timers.ChessTimer.OnTimedEvent(Object sender, ElapsedEventArgs args) in C:\Users\georg\Source\Github\SuperScrabble\src\Server\WebApi\SuperScrabble.WebApi\Timers\ChessTimer.cs:line 120
at SuperScrabble.WebApi.Timers.ChessTimer.<.ctor>b__5_0(Object sender, ElapsedEventArgs args) in C:\Users\georg\Source\Github\SuperScrabble\src\Server\WebApi\SuperScrabble.WebApi\Timers\ChessTimer.cs:line 35
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state)
at System.Threading.QueueUserWorkItemCallback.<>c.<.cctor>b__6_0(QueueUserWorkItemCallback quwi)
at System.Threading.ExecutionContext.RunForThreadPoolUnsafe[TState](ExecutionContext executionContext, Action`1 callback, TState& state)
at System.Threading.QueueUserWorkItemCallback.Execute()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
at System.Threading.Thread.StartCallback()
It seems to me that the _gamesService object which I pass to the CreateInstance() method inside the TimerManager.CreateTimer() method is already disposed or that some of the services it uses internally are.
public GameTimer CreateTimer(GameState gameState)
{
if (gameState.RemainingSecondsByUserNames.Count == 0)
{
return ActivatorUtilities.CreateInstance<StandardTimer>(_serviceProvider, gameState);
}
else
{
return ActivatorUtilities.CreateInstance<ChessTimer>(_serviceProvider, gameState, _gamesService);
}
}
I am not sure if what I am trying to do is correct. I need to use service classes inside my timer classes to perform operations every time the timer ticks. However, I cannot use dependency injection and that's the reason why I use the ActivatorUtilities class to instantiate the object.
I create all timers from a method inside my SignalR hub class:
private async Task StartGameAsync()
{
var gameState = _matchmakingService.GetGameState(UserName);
string gameId = gameState.GameId;
foreach (Player player in gameState.Players)
{
await Groups.AddToGroupAsync(player.ConnectionId!, gameId);
}
var timer = _timerManager.CreateTimer(gameState);
Console.WriteLine(timer.GetType().Name);
_timerManager.AttachTimerToGameState(timer, gameId);
await Clients.Group(gameId).StartGame(gameId);
await UpdateGameStateAsync(gameState);
timer.Start();
}
So my question would be: Is it possible to find a work around of the problem?
If you need any more clarification please feel free to ask me anything. Any help would be greatly appreciated! Thanks

Xamarin Forms Global variable updates slower than code

I have a problem. I am using the following code in my App.xaml.cs:
public static int agentId;
public static List<Agent> agents;
public App()
{
InitializeComponent();
loadingAgents += onLoadingAgents;
LoadAgentList();
MainPage = new MainPage();
}
private event EventHandler loadingAgents = delegate { };
private async void onLoadingAgents(object sender, EventArgs args)
{
Agents = await RestService.GetAgents();
}
private void LoadAgentList()
{
loadingAgents(this, EventArgs.Empty);
}
public static int AgentId
{
get
{
return agentId;
}
set
{
agentId = value;
}
}
public static List<Agent> Agents
{
get
{
if (agents == null)
{
agents = new List<Agent>();
}
return agents;
}
set
{
agents = value;
AgentId = Agents.Min(x => x.Id);
}
}
Now what this simply should do is the following:
On startup, it collects all the Agents from a webcall and puts it in a List<Agent> Agents
Once the List<Agent> Agents is set, it sets the AgentId to the minimum Id of the Agents list
The problem is that in the ViewModel of the MainPage I use those variables that are supposed to be set, but the code of the ViewModel is faster than the code that needs to update the variables.
How can I wait for the variables to finish before hitting this line: MainPage = new MainPage();?
First i don't think it is necessary to use private event EventHandler loadingAgents.Then you get Agents is an asynchronous operation,so MainPage = new MainPage(); has been executed when the method is called(at this time, the Agents may be null).And in general we don't call asynchronous tasks in the constructor to get the data,you could do it in the OnStart() method.
You could try to change like below :
public App()
{
InitializeComponent();
}
protected async override void OnStart()
{
Agents = await RestService.GetAgents();
MainPage = new MainPage();
}

Xamarin C# activity on screen (un)lock event

Just wondering if there is an event In Xamarin for the activity class like OnStart, OnResume, OnPause etc. that gets fired when the user locks or unlocks their screen while the app is open, I've been looking for such an event in documentation etc, but I haven't been able to find it.
If there is no such event, then how can we create it?
Xamarin C# activity on screen (un)lock event
you could create a listener class to listen for android lock screen and unlock events,use broadcast to receive the state of screen.
first create a ScreenListener.cs :
public class ScreenListener
{
private Context mContext;
private ScreenBroadcastReceiver mScreenReceiver;
private static ScreenStateListener mScreenStateListener;
public ScreenListener(Context context)
{
mContext = context;
mScreenReceiver = new ScreenBroadcastReceiver();
}
/**
* screen BroadcastReceiver
*/
private class ScreenBroadcastReceiver : BroadcastReceiver
{
private String action = null;
public override void OnReceive(Context context, Intent intent)
{
action = intent.Action;
if (Intent.ActionScreenOn == action)
{ // screen on
mScreenStateListener.onScreenOn();
}
else if (Intent.ActionScreenOff == action)
{ // screen off
mScreenStateListener.onScreenOff();
}
else if (Intent.ActionUserPresent == action)
{ // unlock
mScreenStateListener.onUserPresent();
}
}
}
/**
* begin to listen screen state
*
* #param listener
*/
public void begin(ScreenStateListener listener)
{
mScreenStateListener = listener;
registerListener();
getScreenState();
}
/**
* get screen state
*/
private void getScreenState()
{
PowerManager manager = (PowerManager)mContext
.GetSystemService(Context.PowerService);
if (manager.IsScreenOn)
{
if (mScreenStateListener != null)
{
mScreenStateListener.onScreenOn();
}
}
else
{
if (mScreenStateListener != null)
{
mScreenStateListener.onScreenOff();
}
}
}
/**
* stop listen screen state
*/
public void unregisterListener()
{
mContext.UnregisterReceiver(mScreenReceiver);
}
/**
* regist screen state broadcast
*/
private void registerListener()
{
IntentFilter filter = new IntentFilter();
filter.AddAction(Intent.ActionScreenOn);
filter.AddAction(Intent.ActionScreenOff);
filter.AddAction(Intent.ActionUserPresent);
mContext.RegisterReceiver(mScreenReceiver, filter);
}
public interface ScreenStateListener
{// Returns screen status information to the caller
void onScreenOn();
void onScreenOff();
void onUserPresent();
}
}
then in the MainActivity.cs:
public class MainActivity : AppCompatActivity,ScreenStateListener
{
ScreenListener mScreenListener;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
mScreenListener = new ScreenListener(this);
}
protected override void OnDestroy()
{
base.OnDestroy();
mScreenListener.unregisterListener();
}
protected override void OnResume()
{
base.OnResume();
mScreenListener.begin(this);
}
public void onScreenOn()
{
Console.WriteLine("onScreenOn");
}
public void onScreenOff()
{
Console.WriteLine("onScreenOff");
}
public void onUserPresent()
{
Console.WriteLine("onUserPresent");
}
}
Here's a sample of Xamarin.Android activities lifecycle.
You can override any of the lifecycle methods like this:
protected override void OnResume() {
base.OnResume();
}
Like in native Android OnPause is fired when the system is about to put the activity into the background. OnResume is called when the activity is ready to start interacting with the user.
OnPause and OnResume can be used for your (un)lock events.

C# ForecastIOPortable lib in WPF application with Timer

I'm trying to get weather information using ForecastIOPortable library.
I have a method that works without problems in Console application, same in WPF application.
ForecastApi api = new ForecastApi("XXXX");
var forecast = api.GetWeatherDataAsync(XXXX, XXXX);
var results = forecast.Result;
int tempC = (int)(5.0 / 9.0 * (results.Currently.Temperature - 32));
Problem shows when I try to call that method with tick of timer, program freezes and VS doesn't show information about exception.
When I checked breakpoints, I get information that results doesn't change and all time has value=null.
What is the reason of problem and how to deal with it?
You are using an async process so you will you will be getting the a Task rather than the result.
In a console app you generally have to .Wait() for the task to resolve before the result will be populated. You would be better to test using a WPF application where you can await the GetWeatherDataAsync method.
Probably the best way to handle it is to wrap the timer in a class and pass in the various bits.
You can try this
public class ForecastApiAsyncTimer : IDisposable
{
private ForecastApi _api;
private Timer _timer;
public ForecastApiAsyncTimer(Timer timer, ForecastApi forecastApi)
{
if (timer == null)
throw new ArgumentNullException("timer");
if (forecastApi == null)
throw new ArgumentNullException("forecastApi");
_api = forecastApi;
_timer = timer;
_timer.Elapsed += _timer_Elapsed;
}
public ForecastApiAsyncTimer(double interval, ForecastApi forecastApi)
{
if (forecastApi == null)
throw new ArgumentNullException("forecastApi");
_api = forecastApi;
_timer = new Timer(interval);
_timer.Elapsed += _timer_Elapsed;
}
public void Start()
{
_timer.Start();
}
public void Stop()
{
_timer.Stop();
}
protected async virtual Task<int> TimerElapsedTask()
{
var forecast = await _api.GetWeatherDataAsync(40.7505045d, -73.9934387d);
int tempC = (int)(5.0 / 9.0 * (forecast.Currently.Temperature - 32));
return tempC;
}
async void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
int result = await TimerElapsedTask();
// do something with result.
}
~ForecastApiAsyncTimer()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing || _timer == null)
return;
_timer.Dispose();
_timer = null;
}
}
Example usage 1.
static void Main(string[] args)
{
string apiKey = "yourApiKey";
ForecastApi api = new ForecastApi(apiKey);
using (var forecastTimer = new ForecastApiAsyncTimer(5000, api))
{
forecastTimer.Start();
while (!Console.KeyAvailable)
{
}
}
}
Example usage 2:
static void Main(string[] args)
{
string apiKey = "yourApiKey";
ForecastApi api = new ForecastApi(apiKey);
Timer timer = new Timer(5000);
var forecastTimer = new ForecastApiAsyncTimer(timer, api);
forecastTimer.Start();
while (!Console.KeyAvailable)
{
}
}

switching from different timers c#

I'm creating an Windowns phone 8 app(c#), its a countdown interval timer, so there is prepare time(10 sec), work time(20 sec), rest time(10 sec). I have these variables
`TimeSpan prepInterval = new TimeSpan(0, 0, 0, 10);
TimeSpan workInterval = new TimeSpan(0, 0, 0, 20);
TimeSpan restInterval = new TimeSpan(0, 0, 0, 10);`
I can't wrap my head around having them implementing them one after another when they hit 0. So when prepare time is done, the work timer is to start and when thats finised, the rest timer is to start.
If you would like to have some more broken down logic in all of this, maybe you can create some classes based on a simple interface, like the following:
interface ITimerAction
{
int Seconds { get; set; }
bool Started { get; }
bool Completed { get; }
void OnStart();
void OnComplete();
}
interface ITimerActionList
{
void Add(ITimerAction action);
void Work();
event EventHandler OnCompletedEvent;
}
This would then allow you to create an abstract TimerAction class, and TimerActionList
abstract class TimerAction : ITimerAction
{
public virtual int Seconds
{
get;
set;
}
public virtual bool Completed
{
get;
protected set;
}
public virtual bool Started
{
get;
protected set;
}
public abstract void OnStart();
public abstract void OnComplete();
}
class TimerActionList : ITimerActionList
{
public event EventHandler OnCompletedEvent;
private readonly IList<ITimerAction> actions = new List<ITimerAction>();
private bool working = false;
private Thread myThread;
public void Add(ITimerAction action)
{
if (working)
{
throw new InvalidOperationException("Cannot add new timers when work is already in progress");
}
actions.Add(action);
}
protected virtual void DoWork()
{
working = true;
int currentStep = 0, maxSteps = actions.Count;
while (currentStep < maxSteps)
{
ITimerAction action = actions[currentStep];
if (!action.Started)
{
action.OnStart();
}
if (action.Completed)
{
currentStep++;
continue;
}
if (action.Seconds == 0)
{
action.OnComplete();
continue;
}
action.Seconds--;
Thread.Sleep(1000);
}
Completed();
}
public void Work()
{
if (working)
{
throw new InvalidOperationException("Already running!");
}
working = true;
myThread = new Thread(DoWork);
myThread.Start();
}
protected virtual void Completed()
{
myThread = null;
working = false;
actions.Clear();
var local = OnCompletedEvent;
if (local != null)
{
local.Invoke(this, EventArgs.Empty);
}
}
}
You could then write the classes that inherit from the TimerAction class, that could handle an action before and after the timer ran through :)
class PrepareTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Preparing");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Prepare ready");
Completed = true;
}
}
class WorkTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Working");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Work ready");
Completed = true;
}
}
class CoolDownTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Cooling down");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Cooldown ready");
Completed = true;
}
}
And then you could test the code as such
static void Main(string[] args)
{
bool done = false;
ITimerActionList mylist = new TimerActionList();
mylist.Add(new PrepareTimer { Seconds = 1 });
mylist.Add(new WorkTimer { Seconds = 2 });
mylist.Add(new CoolDownTimer { Seconds = 1 });
mylist.OnCompletedEvent += (sender, e) =>
{
done = true;
};
mylist.Work();
while (!done)
{
// timer is running
}
Console.WriteLine("Done!");
}
(Console program, but i guess that also goes to demonstrate?)
Here's an example based on deathismyfriend's and Hans Passant's suggestions:
var start = new DateTime();
var stage = 0;
var timer = new System.Timers.Timer(100);
timer.Elapsed += (s, e) =>
{
var elapsed = DateTime.Now - start;
int duration = stage == 1 ? 20 : 10;
if (elapsed.TotalSeconds > duration)
{
start = DateTime.Now;
stage++;
if (stage > 2)
timer.Stop();
}
};
start = DateTime.Now;
stage = 0;
timer.Start();

Categories