<repo_name>CMorooney/SpyTag2<file_sep>/SpyTag2.0/MainActivity.cs
﻿using System;
using Android.App;
using Android.Support.V4.App;
using Android.Content.PM;
using Android.Widget;
using Android.OS;
using Color = Android.Graphics.Color;
using Int = Java.Lang.Integer;

namespace SpyTag2
{
	[Activity (Label = "SpyTag", MainLauncher = true, Icon = "@drawable/app_icon", LaunchMode = LaunchMode.SingleTask)]
	public class MainActivity : Activity
	{
	
		bool HasBeenPrompted;
		AlertDialog PlayPrompt;

		#region layout variables
		TextView Text;
		TextView CountdownText;
		#endregion

		protected override void OnCreate (Bundle bundle){
			base.OnCreate (bundle);

			HasBeenPrompted = false;

			SetContentView (Resource.Layout.Main);

			Text = FindViewById<TextView>(Resource.Id.text);
			CountdownText = FindViewById<TextView> (Resource.Id.countdown);

			//create alert dialog to prompt user of "challenge" and respond appropriately
			var promptBuilder = new AlertDialog.Builder (this)
				.SetPositiveButton ("Yes", (s, args) => {
					//keep play state updated!
					((ApplicationState)Application).PlayState = PlayState.AcceptedChallenge;
					Console.WriteLine ("************ CHALLENGE ACCEPTED *************");

					((ApplicationState)Application).Timer.Stop();

					//set seconds to countdown before player loses
					((ApplicationState)Application).SecondsToCountDown = 20;

					((ApplicationState)Application).Timer.Start();
				})
					.SetNegativeButton ("No", (s, args) => {
					//keep play state updated!
					((ApplicationState)Application).PlayState = PlayState.Coward;

					((ApplicationState)Application).Timer.Stop();

					RunOnUiThread(() => Text.Text = "Coward.");
			});

			PlayPrompt = promptBuilder.Create ();
			PlayPrompt.SetMessage ("Will you attempt to disarm? 5 Seconds to comply...");
			PlayPrompt.SetTitle ("Tag nearby!");
		}

		void HandleTimerTick (){
			//only tick if activity is running
			if (!IsFinishing) {
				if (((ApplicationState)Application).SecondsToCountDown == 0) {
					((ApplicationState)Application).Timer.Stop ();

					switch (((ApplicationState)Application).PlayState) {
					case PlayState.InRange:
						PlayPrompt.Dismiss ();
						((ApplicationState)Application).PlayState = PlayState.Coward;
						RunOnUiThread (() => Text.Text = "Coward.");
						break;
					case PlayState.AcceptedChallenge:
						RunOnUiThread (() => {
							Text.Text = "You've been tagged";
							CountdownText.Text = String.Empty;
						});
						break;
					}
				} else {
					((ApplicationState)Application).SecondsToCountDown--;
					switch (((ApplicationState)Application).PlayState) {
					case PlayState.InRange:
						RunOnUiThread (() => PlayPrompt.SetMessage ("Will you attempt to disarm? " + ((ApplicationState)Application).SecondsToCountDown + " Seconds to comply..."));
						break;
					case PlayState.AcceptedChallenge:
						RunOnUiThread (() => CountdownText.Text = "You have " + ((ApplicationState)Application).SecondsToCountDown + " seconds to find the tag");
						break;
					}
				}
			}
		}

		void HandleRadiusExit (){
			((ApplicationState)Application).PlayState = PlayState.Idle;

			RunOnUiThread(() => Text.Text = "Bye bye, tag");
		}

		void HandleRadiusEnter (){
			((ApplicationState)Application).PlayState = PlayState.InRange;

			RunOnUiThread (() => {
				Text.Text = "Yo there's something nearby";
			});
		}

		void HandleProximityImmediate (){
			RunOnUiThread (() => {
				if(((ApplicationState)Application).PlayState == PlayState.AcceptedChallenge){
					Text.Text = "Tag Disarmed!";
					((ApplicationState)Application).PlayState = PlayState.CompletedChallenge;
					((ApplicationState)Application).Timer.Stop();
				}
			});
		}

		void HandleProximityFar (){
			RunOnUiThread (() => Text.Text = "Tag Detected: far");
		}

		void HandleProximityClose (){
			RunOnUiThread (() => {
				if (!HasBeenPrompted && !((ApplicationState)Application).IsInBackground && !IsFinishing) {
					HasBeenPrompted = true;

					//this should start at 5 for initial prompt to play
					((ApplicationState)Application).SecondsToCountDown = 5;

					//start countdown timer to accept
					((ApplicationState)Application).Timer.Start();

					//show prompt to play
					PlayPrompt.Show ();

					Text.Text = "Tag Detected: close";
				}
			});
		}

		protected override void OnPause (){
			base.OnPause ();

			((ApplicationState)Application).IsInBackground = true;
			((ApplicationState)Application).BeaconManager.SetBackgroundMode (((ApplicationState)Application), true);
		}

		protected override void OnResume ()
		{
			base.OnResume ();

			((ApplicationState)Application).IsInBackground = false;
			((ApplicationState)Application).BeaconManager.SetBackgroundMode (((ApplicationState)Application), false);

			//subscribe to Application Events. These need to be in OnResume so they don't get called before Activity is running
			((ApplicationState)Application).ProximityClose += HandleProximityClose;
			((ApplicationState)Application).ProximityFar += HandleProximityFar;
			((ApplicationState)Application).ProximityImmediate += HandleProximityImmediate;
			((ApplicationState)Application).RadiusExit += HandleRadiusExit;
			((ApplicationState)Application).RadiusEnter += HandleRadiusEnter;
			((ApplicationState)Application).TimerTick += HandleTimerTick;
		}
	}
}


<file_sep>/SpyTag2.0/Enums/PlayState.cs
﻿using System;

namespace SpyTag2
{
	public enum PlayState
	{
		Idle,
		InRange,
		AcceptedChallenge,
		CompletedChallenge,
		Coward
	}
}

<file_sep>/SpyTag2.0/ApplicationState.cs
﻿using System;

using Android.App;
using Android.Content;
using System.Linq;
using System.Timers;
using Android.Runtime;
using RadiusNetworks.IBeaconAndroid;
using Color = Android.Graphics.Color;
using Int = Java.Lang.Integer;

namespace SpyTag2
{
	public delegate void ProximityClose();
	public delegate void ProximityFar();
	public delegate void ProximityImmediate();
	public delegate void RadiusEnter();
	public delegate void RadiusExit();
	public delegate void TimerTick();

	[Application]
	public class ApplicationState : Application, IBeaconConsumer
	{
		public event ProximityClose ProximityClose;
		public event ProximityFar ProximityFar;
		public event ProximityImmediate ProximityImmediate;
		public event RadiusExit RadiusExit;
		public event RadiusEnter RadiusEnter;
		public event TimerTick TimerTick;

		const string UUID = "01122334-4556-6778-899a-abbccddeeff0";
		const string TagId = "Bomb";

		public PlayState PlayState;
		public IBeaconManager BeaconManager;
		public int SecondsToCountDown;
		public Timer Timer;
		public bool IsInBackground;
		public bool HasBeenNotified;

		MonitorNotifier MonitoringNotifier;
		RangeNotifier RangeNotifier;
		Region MonitoringRegion, RangingRegion;

		public ApplicationState (IntPtr handle, JniHandleOwnership ownerShip) : base(handle, ownerShip){}


		public override void OnCreate (){
			base.OnCreate ();

			HasBeenNotified = false;

			BeaconManager = IBeaconManager.GetInstanceForApplication (this);
			MonitoringNotifier = new MonitorNotifier ();
			RangeNotifier = new RangeNotifier ();

			//set to idle on load
			PlayState = PlayState.Idle;

			Int maj = (Int)1;
			Int min = (Int)104;

			MonitoringRegion = new Region (TagId, UUID, maj, min);
			RangingRegion = new Region (TagId, UUID, maj, min);

			MonitoringNotifier.EnterRegionComplete += EnteredRadius;
			MonitoringNotifier.ExitRegionComplete += ExitedRadius;

			//bind beacon manager to application so it doens't die in backgrounding
			//set background scan intervals
			BeaconManager.Bind (this);
			BeaconManager.SetBackgroundScanPeriod (1500);
			BeaconManager.SetBackgroundBetweenScanPeriod (1500);

			RangeNotifier.DidRangeBeaconsInRegionComplete += DistanceToRegionChanged;

			//enabled timer that elapses every 1.5 second
			Timer = new Timer {
				Interval = 1500
			};
			Timer.Elapsed += TimerElapsed;
		}

		void TimerElapsed (object sender, ElapsedEventArgs e){
			TimerTick ();
		}

		void DistanceToRegionChanged (object sender, RangeEventArgs e){
			if (e.Beacons.Count > 0 && PlayState != PlayState.Coward && PlayState != PlayState.CompletedChallenge) {
				var beacon = e.Beacons.FirstOrDefault ();

				switch ((ProximityType)beacon.Proximity) {
				case ProximityType.Immediate:
					ProximityImmediate ();
					break;
				case ProximityType.Near:
					if (IsInBackground && !HasBeenNotified) {
						HasBeenNotified = true;

						var intent = new Intent (this, typeof(MainActivity));

						TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);
						stackBuilder.AddNextIntent(intent);

						PendingIntent pendingIntent = stackBuilder.GetPendingIntent(0, PendingIntentFlags.UpdateCurrent);

						// Instantiate the builder and set notification elements:
						var builder = new Notification.Builder (this)
							.SetContentTitle ("Tag Nearby!")
							.SetContentText ("Tap To Accept")
							.SetContentIntent (pendingIntent)
							.SetSmallIcon (Resource.Drawable.notification_icon)
							.SetDefaults(NotificationDefaults.All);

						// Build the notification:
						Notification notification = builder.Build ();

						// Get the notification manager:
						NotificationManager notificationManager =
							GetSystemService (NotificationService) as NotificationManager;

						// Publish the notification:
						const int notificationId = 0;
						notificationManager.Notify (notificationId, notification);
					} else {
						ProximityClose ();
					}
					break;
				case ProximityType.Far:
					ProximityFar ();
					break;
				case ProximityType.Unknown:
					break;
				}
			}
		}

		void ExitedRadius (object sender, MonitorEventArgs e){
			RadiusExit ();
		}

		void EnteredRadius (object sender, MonitorEventArgs e){
			RadiusEnter ();
		}

		public void OnIBeaconServiceConnect(){
			BeaconManager.SetMonitorNotifier(MonitoringNotifier);
			BeaconManager.SetRangeNotifier(RangeNotifier);

			BeaconManager.StartMonitoringBeaconsInRegion(MonitoringRegion);
			BeaconManager.StartRangingBeaconsInRegion(RangingRegion);
		}
	}
}

