/// <summary> /// Quick function to animate the camera to a location /// on the map. /// </summary> /// <param name="lat">Latitude to move to.</param> /// <param name="lon">Longitude to move to.</param> /// <param name="zoom">Level to zoom to over 100ms.</param> public void AnimateCameraTo(double lat, double lon, float zoom = 0) { try { if (zoom == 0) { zoom = KCApi.Properties.Renderer.NativeMap.CameraPosition.Zoom; } Device.BeginInvokeOnMainThread(() => { if (KCApi.Properties.MapReady && KCApi.Properties.RenderReady && NativeMap != null) { lock (nativeMapLock) { NativeMap.AnimateCamera(CameraUpdateFactory.NewLatLngZoom(new LatLng(lat, lon), zoom), 100, null); } } }); } catch (Exception e) { KCApi.OutputException(e); } }
/// <summary> /// Function to start map and get ride location. /// </summary> /// <param name="sender">Event sender.</param> /// <param name="e">Event args.</param> public void Button_Clicked(object sender, EventArgs e) { if (KCApi.Properties.State == KCProperties.AppState.Accept) { lock (buttonLock) { StatusColor.IsEnabled = false; Ride ride = new Ride(); KCApi.Properties.CurrentPosition = Task.Run(async() => await KCApi.GetCurrentPosition()).Result; if (KCApi.Properties.CurrentPosition.Latitude == 0 && KCApi.Properties.CurrentPosition.Longitude == 0) { var text = "GPS signal lost. Please reenable or reenter service."; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); } else if (KCApi.Properties.RideStatus != KCProperties.RideStatuses.Active && KCApi.AcceptNextRide(ride) && KCApi.SetRideLocation(ride, KCApi.Properties.CurrentPosition.Latitude, KCApi.Properties.CurrentPosition.Longitude)) { lock (KCApi.Properties.StateLock) { KCApi.Properties.State = KCProperties.AppState.Transitioning; //Start takes only a position, which will come from the database ride.SetDisplayAddress(KCApi.GetAddressFromPosition(new Position(ride.ClientLat, ride.ClientLong))); KCApi.Start(ride); Navigation.PushAsync(new MapPage()); } } else if (!Driver_Id.authenticated) { var text = "Authentication Failure"; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); if (KCApi.Properties.State == KCProperties.AppState.Accept) { lock (KCApi.Properties.StateLock) { KCApi.Properties.State = KCProperties.AppState.Transitioning; Navigation.PopAsync(); } } } else if (Status.Text == "No available rides") { var text = "No available rides."; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); } else { var text = "Accept ride failed."; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); } StatusColor.IsEnabled = true; } } }
/// <summary> /// Executes everytime the page appears. /// Changes the app state and starts the update timer. /// </summary> protected override async void OnAppearing() { base.OnAppearing(); if (KCApi.Properties.State != KCProperties.AppState.Accept) { KCApi.Properties.State = KCProperties.AppState.Accept; Timer(null, null); if (KCApi.Properties.NetState == KCProperties.NetworkState.Disconnected) { lock (KCApi.Properties.StateLock) KCApi.Properties.State = KCProperties.AppState.Transitioning; await Navigation.PopAsync(); return; } KCApi.Properties.CurrentPosition = await KCApi.GetCurrentPosition(); // Location is not set if (KCApi.Properties.CurrentPosition.Latitude == 0 && KCApi.Properties.CurrentPosition.Longitude == 0) { var text = "GPS signal lost. Please reenable or reenter service."; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); } // Driver is no longer authenticated. Send back to sign in else if (!Driver_Id.authenticated) { var text = "Authentication Failure"; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); lock (KCApi.Properties.StateLock) KCApi.Properties.State = KCProperties.AppState.Transitioning; await Navigation.PopAsync(); } // Driver has entered the Accept screen for the first time since logging in as CurrentRide is null else if (KCApi.Properties.RideStatus != KCProperties.RideStatuses.Active && KCApi.Properties.CurrentRide == null) { Ride ride = new Ride(); if (KCApi.RecoveryCheck(ride) && KCApi.SetRideLocation(ride)) { ride.SetDisplayAddress(KCApi.GetAddressFromPosition(new Position(ride.ClientLat, ride.ClientLong))); KCApi.Start(ride); lock (KCApi.Properties.StateLock) KCApi.Properties.State = KCProperties.AppState.Transitioning; await Navigation.PushAsync(new MapPage()); } } updater.Start(); } }
/// <summary> /// If the driver already has a ride it sets the ride id to that ride /// in case of failure or lost connection. /// </summary> /// <param name="ride">Ride object to store recovery info in.</param> /// <returns>True upon receipt of a success response, false otherwise.</returns> public static bool RecoveryCheck(Ride ride) { string message = "https://" + ip + "/driver/recoveryCheck.php?token=" + Driver_Id.token + "&driverID=" + Driver_Id.driver_Id; // Create a request for the URL. WebRequest request = WebRequest.Create(message); request.Timeout = timeout; // Get the response. string responseFromServer = ""; try { HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Get the stream containing content returned by the server. Stream dataStream = response.GetResponseStream(); // Open the stream using a StreamReader for easy access. StreamReader reader = new StreamReader(dataStream); // Read the content. responseFromServer = reader.ReadToEnd(); // Cleanup the streams and the response. reader.Close(); dataStream.Close(); response.Close(); dynamic jObject = null; if (!responseFromServer.Contains("Failure") && !responseFromServer.Contains("No")) { jObject = JObject.Parse(responseFromServer); ride.SetRideID(Int32.Parse((string)jObject.result.rideID)); ride.SetRidePhoneNum((string)jObject.result.phone); ride.SetName((string)jObject.result.name); return(true); } //If the response comes back as Authentication failure then set the driver as not authenticated. else if (responseFromServer.Contains("Authentication failure")) { Driver_Id.authenticated = false; return(false); } return(false); } catch (WebException) { lock (Properties.NetworkStateLock) KCApi.Properties.NetState = KCProperties.NetworkState.Disconnected; return(false); } catch (Exception e) { KCApi.OutputException(e); return(false); } }
/// <summary> /// makes sure that the app has permission to access the /// location and resets KCApi everytime the sign in page appears. /// </summary> protected override async void OnAppearing() { if (KCApi.Properties.State != KCProperties.AppState.SignIn) { KCApi.Properties.State = KCProperties.AppState.SignIn; KCApi.Reset(); KCApi.Properties.HaveLocationPermission = await RequestPermission(Plugin.Permissions.Abstractions.Permission.Location); } }
/// <summary> /// Attempts to authenticate the user. Returns true if the user /// is authenticated with the server, false upon error or rejection. /// </summary> /// <param name="password">Password to include in the query.</param> /// <param name="userName">Username to include in the query.</param> /// <returns></returns> public static bool Authenticate(string password, string userName) { string message = "https://" + ip + "/driver/auth/authenticate.php?username="******"&pwHsh=" + GetHash(password, userName); string responseFromServer = ""; try { // Create a request for the URL. WebRequest request = WebRequest.Create(message); request.Timeout = timeout; // Get the response. HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Get the stream containing content returned by the server. Stream dataStream = response.GetResponseStream(); // Open the stream using a StreamReader for easy access. StreamReader reader = new StreamReader(dataStream); // Read the content. responseFromServer = reader.ReadToEnd(); // Cleanup the streams and the response. reader.Close(); dataStream.Close(); response.Close(); dynamic jObject = null; if (!responseFromServer.Contains("Failure")) { jObject = JObject.Parse(responseFromServer); Driver_Id.driver_Id = Int32.Parse((string)jObject.result.driverID); Driver_Id.token = (string)jObject.result.token; Driver_Id.authenticated = true; return(true); } else { return(false); } } catch (WebException) { lock (Properties.NetworkStateLock) KCApi.Properties.NetState = KCProperties.NetworkState.Disconnected; return(false); } catch (Exception e) { KCApi.OutputException(e); return(false); } }
/// <summary> /// Updates the remote server on the current location of the driver without getting ride info. /// </summary> /// <param name="latitude">Current latitude of the driver.</param> /// <param name="longitude">Current longitude of the driver.</param> /// <returns></returns> public static bool SetDriverLocation(double latitude, double longitude) { string message = "https://" + ip + "/driver/updateLocation.php?driverID=" + Driver_Id.driver_Id + "&token=" + Driver_Id.token + "&lat=" + latitude + "&lon=" + longitude; string responseFromServer = ""; try { // Create a request for the URL. WebRequest request = WebRequest.Create(message); request.Timeout = timeout; // Get the response. HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Get the stream containing content returned by the server. Stream dataStream = response.GetResponseStream(); // Open the stream using a StreamReader for easy access. StreamReader reader = new StreamReader(dataStream); // Read the content. responseFromServer = reader.ReadToEnd(); // Cleanup the streams and the response. reader.Close(); dataStream.Close(); response.Close(); } catch (WebException) { lock (Properties.NetworkStateLock) KCApi.Properties.NetState = KCProperties.NetworkState.Disconnected; return(false); } catch (Exception e) { KCApi.OutputException(e); return(false); } //If the response comes back as Authentication failure then set the driver as not authenticated. if (responseFromServer.Contains("Authentication failure") || responseFromServer.Contains("Unable to authenticate")) { Driver_Id.authenticated = false; return(false); } if (!responseFromServer.Contains("error")) { return(true); } return(false); }
/// <summary> /// Gets the salt for a user in order to hash their password. /// </summary> /// <param name="userName">Username from which to get the salt.</param> /// <returns>string containing the salt.</returns> public static string GetSalt(string userName) { string message = "https://" + ip + "/driver/auth/getSalt.php?username="******""; try { // Create a request for the URL. WebRequest request = WebRequest.Create(message); request.Timeout = timeout; // Get the response. HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Display the status. // Get the stream containing content returned by the server. Stream dataStream = response.GetResponseStream(); // Open the stream using a StreamReader for easy access. StreamReader reader = new StreamReader(dataStream); // Read the content. responseFromServer = reader.ReadToEnd(); // Display the content. // Cleanup the streams and the response. reader.Close(); dataStream.Close(); response.Close(); dynamic jObject = null; if (!responseFromServer.Contains("Failure")) { jObject = JObject.Parse(responseFromServer); return((string)jObject.result.pwSlt); } else { return("error"); } } catch (WebException) { lock (Properties.NetworkStateLock) KCApi.Properties.NetState = KCProperties.NetworkState.Disconnected; return("No Internet connection."); } catch (Exception e) { KCApi.OutputException(e); return("Error Connecting to Server"); } }
/// <summary> /// Decouples the driver from the ride and puts the ride back in the queue. /// </summary> /// <param name="ride">Ride object to cancel.</param> /// <returns>True upon receipt of a success response, false otherwise.</returns> public static bool CancelRide(Ride ride) { string message = "https://" + ip + "/driver/decouple.php?" + "rideID=" + ride.RideId + "&token=" + Driver_Id.token + "&driverID=" + Driver_Id.driver_Id; string responseFromServer = ""; // Create a request for the URL. WebRequest request = WebRequest.Create(message); request.Timeout = timeout; try { // Get the response. HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Get the stream containing content returned by the server. Stream dataStream = response.GetResponseStream(); // Open the stream using a StreamReader for easy access. StreamReader reader = new StreamReader(dataStream); // Read the content. responseFromServer = reader.ReadToEnd(); // Cleanup the streams and the response. reader.Close(); dataStream.Close(); response.Close(); } catch (WebException) { lock (Properties.NetworkStateLock) KCApi.Properties.NetState = KCProperties.NetworkState.Disconnected; return(false); } catch (Exception e) { KCApi.OutputException(e); return(false); } if (!responseFromServer.Contains("error")) { return(true); } return(false); }
/// <summary> /// Timer function which updates the driver if there are any rides in the queue. /// </summary> private void Timer(Object source, ElapsedEventArgs e) { if (KCApi.Properties.State == KCProperties.AppState.Accept) { string status = Task.Run(() => KCApi.CheckQueue()).Result; if (KCApi.RecoveryCheck(new Ride())) { status = "Active ride ongoing"; } if (KCApi.Properties.NetState == KCProperties.NetworkState.Disconnected) { var text = "Internet connection lost."; lock (KCApi.Properties.StateLock) { Device.BeginInvokeOnMainThread(async() => { Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); KCApi.Properties.State = KCProperties.AppState.Transitioning; await Navigation.PopAsync(); }); return; } } Device.BeginInvokeOnMainThread(() => { Status.Text = status; if (status.Equals("Rides are available")) { StatusColor.BackgroundColor = Color.Green; } else { StatusColor.BackgroundColor = Color.Gray; } }); updater.Interval = 500; // Can optimize to reduce interval depending on time taken } }
/// <summary> /// Moves the camera directly to the given coordinates. /// </summary> /// <param name="lat">Latitude to move to.</param> /// <param name="lon">Longitude to move to.</param> public void MoveCameraTo(double lat, double lon) { try { Device.BeginInvokeOnMainThread(() => { if (KCApi.Properties.MapReady && KCApi.Properties.RenderReady && NativeMap != null) { lock (nativeMapLock) { NativeMap.MoveCamera(CameraUpdateFactory.NewLatLng(new LatLng(lat, lon))); } } }); } catch (Exception e) { KCApi.OutputException(e); } }
/// <summary> /// Updates the address text when the ride is updated. /// </summary> public async void UpdateText() { if (KCApi.Properties.State == KCProperties.AppState.Map) { await Task.Run(() => { while (KCApi.Properties.CurrentRide == null) { ; } KCApi.Properties.CurrentRide.SetDisplayAddress(KCApi.GetAddressFromPosition(new Position(KCApi.Properties.CurrentRide.ClientLat, KCApi.Properties.CurrentRide.ClientLong))); Device.BeginInvokeOnMainThread(() => { RiderCardText.Text = KCApi.Properties.CurrentRide.ClientName + ": " + KCApi.Properties.CurrentRide.DisplayAddress; }); }); } }
/// <summary> /// Function to update the GoogleMap with the new /// position of the rider marker. /// </summary> public void UpdateMarker() { lock (nativeMapLock) { Device.BeginInvokeOnMainThread(() => { try { NativeMap.Clear(); riderPin = KCPin.CreateRiderPin(new Position(KCApi.Properties.CurrentRide.ClientLat, KCApi.Properties.CurrentRide.ClientLong)); MarkerOptions mo = riderPin.CreateMarker(); NativeMap.AddMarker(mo); } catch (Exception e) { KCApi.OutputException(e); } }); } }
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); Plugin.CurrentActivity.CrossCurrentActivity.Current.Init(this, savedInstanceState); Forms.Init(this, savedInstanceState); Xamarin.FormsMaps.Init(this, savedInstanceState); TabLayoutResource = Resource.Layout.Tabbar; ToolbarResource = Resource.Layout.Toolbar; var width = Resources.DisplayMetrics.WidthPixels; var height = Resources.DisplayMetrics.HeightPixels; var density = Resources.DisplayMetrics.Density; KCApp.ScreenWidth = (width - 0.5f) / density; KCApp.ScreenHeight = (height - 0.5f) / density; KCApi.Initialize(); LoadApplication(new KCApp()); }
/// <summary> /// When a ride is completed rideactive is set to false and the ride is compleated. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void ButtonCompleteRide(object sender, EventArgs e) { if (KCApi.Properties.State != KCProperties.AppState.Map) { return; } ButtonDisable(); if (!KCApi.CompleteRide(KCApi.Properties.CurrentRide)) { var text = "There was a problem completing the ride."; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); } else { var text = "The Ride has been completed."; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); KCApi.Properties.RideStatus = KCProperties.RideStatuses.Completed; } ButtonEnable(); }
/// <summary> /// When the cancel button is pressed rideactive is set to false. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void ButtonCancelRide(object sender, EventArgs e) { if (KCApi.Properties.State != KCProperties.AppState.Map) { return; } ButtonDisable(); if (!KCApi.CancelRide(KCApi.Properties.CurrentRide)) { var text = "There was a problem with cancellation."; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); } else { var text = "The Ride has been canceled."; KCApi.Properties.RideStatus = KCProperties.RideStatuses.CanceledByDriver; Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); } ButtonEnable(); }
//Timer which checks if the driver is still authenticated if they aren't it kicks them back to the login page. public void CheckActive(Object source, ElapsedEventArgs e) { if (KCApi.Properties.State != KCProperties.AppState.Map) { return; } Task.Run(() => { try { bool pop = false; if (!Driver_Id.authenticated && KCApi.Properties.RideStatus == KCProperties.RideStatuses.Active) { pop = true; } //If the ride is inactive then pop back to the Accept page. else if (KCApi.Properties.RideStatus != KCProperties.RideStatuses.Active && KCApi.Properties.RenderReady) { if (KCApi.Properties.RideStatus == KCProperties.RideStatuses.CanceledByRider) { var text = "Rider has cancelled ride."; Device.BeginInvokeOnMainThread(() => { Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); }); } pop = true; } else if (KCApi.Properties.NetState == KCProperties.NetworkState.Disconnected) { var text = "Internet connection lost."; Device.BeginInvokeOnMainThread(() => { Toast.MakeText(CrossCurrentActivity.Current.Activity, text, ToastLength.Short).Show(); }); pop = true; } if (pop) { KCApi.Stop(); activeTimer.Stop(); lock (KCApi.Properties.StateLock) { KCApi.Properties.State = KCProperties.AppState.Transitioning; Device.BeginInvokeOnMainThread(async() => { await Navigation.PopAsync(); }); } } else { activeTimer.Interval = 100.0f; // Can be optimized } } catch (Exception ex) { KCApi.OutputException(ex); } }); }
/// <summary> /// Sets the clients postion in the given Ride by querying /// the remote server /// </summary> /// <param name="ride">The ride to store the location retrieved in.</param> /// <param name="latitude">Current latitude of the driver.</param> /// <param name="longitude">Current longitude of the driver.</param> /// <returns>True upon success, false upon failure</returns> public static bool SetRideLocation(Ride ride, double latitude = 0, double longitude = 0) { string message = "https://" + ip + "/driver/rideStatus.php?driverID=" + Driver_Id.driver_Id + "&token=" + Driver_Id.token + "&rideID=" + ride.RideId; if (Properties.CurrentPosition.Latitude != 0 || Properties.CurrentPosition.Longitude != 0) { message += "&lat=" + latitude + "&lon=" + longitude; } // Create a request for the URL. WebRequest request = WebRequest.Create(message); request.Timeout = timeout; // Get the response. string responseFromServer = ""; try { HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Get the stream containing content returned by the server. Stream dataStream = response.GetResponseStream(); // Open the stream using a StreamReader for easy access. StreamReader reader = new StreamReader(dataStream); // Read the content. responseFromServer = reader.ReadToEnd(); // Cleanup the streams and the response. reader.Close(); dataStream.Close(); response.Close(); } catch (WebException) { lock (Properties.NetworkStateLock) KCApi.Properties.NetState = KCProperties.NetworkState.Disconnected; return(false); } catch (Exception e) { KCApi.OutputException(e); return(false); } //If the response comes back as Authentication failure then set the driver as not authenticated. if (responseFromServer.Contains("Authentication failure") || responseFromServer.Contains("Unable to authenticate")) { Driver_Id.authenticated = false; return(false); } // If the response is "Ride not found", the user has canceled. else if (responseFromServer.Contains("Ride not found")) { Properties.RideStatus = KCProperties.RideStatuses.CanceledByRider; } //check if there are any other errors else if (!responseFromServer.Contains("error")) { try { //If there are no errors add the lat and long to the ride class and return true.\ dynamic jObject = JObject.Parse(responseFromServer); double rideLat = Double.Parse((string)jObject.result.lat); double rideLong = Double.Parse((string)jObject.result.lon); ride.SetPosition(rideLat, rideLong); return(true); } catch (Exception e) { KCApi.OutputException(e); return(false); } } return(false); }
/// <summary> /// Attempts to sign the user in. If location permissions are /// denied and denied again, the app is killed. /// </summary> /// <param name="sender">Event sender.</param> /// <param name="e">Event args.</param> private void SignInClicked(object sender, EventArgs e) { lock (buttonLock) { if (KCApi.Properties.State == KCProperties.AppState.SignIn) { //only allow the user to get to the next page if the username and password are correct. if (KCApi.Properties.HaveLocationPermission) { if ((!String.IsNullOrEmpty(username.Text) || !String.IsNullOrEmpty(password.Text)) && KCApi.Authenticate(password.Text, username.Text)) { KCApi.Properties.State = KCProperties.AppState.Transitioning; KCApi.Properties.NetState = KCProperties.NetworkState.Connected; //reset the username and password fields. username.Text = ""; password.Text = ""; Navigation.PushAsync(new AcceptPage()); } else { //The username or password is incorrect. var text = "Check your network connection and credentials and try again."; DisplayAlert("Authentication Failure", text, "OK"); } } else { var alertDialog = new Android.App.AlertDialog.Builder(CrossCurrentActivity.Current.Activity); alertDialog.SetTitle("Location Needed"); alertDialog.SetMessage("You must allow this app to use your location. Allow and try again."); alertDialog.SetPositiveButton("OK", async(senderad, args) => { KCApi.Properties.HaveLocationPermission = await RequestPermission(Plugin.Permissions.Abstractions.Permission.Location); }); alertDialog.SetNegativeButton("Cancel", (senderad, args) => { System.Diagnostics.Process.GetCurrentProcess().Kill(); }); alertDialog.Create().Show(); } } } }