How to detect call hang up in windows phone 10 - c#

I want to programmatically detect when call hang up in UWP app for windows phone 10.
I see Caller ID sample and see Communication blocking and filtering sample too.
But I don't find simple solution for detect when call hang up. I found CallHistoryChanged trigger and I think my complex solution is read call history when call history changed trigger and get last incoming call.
Is there any simple solution for detect call hang up?
Is my solution is correct?
Is there a better solution than my solution?

Is there any simple solution for detect call hang up?
Is my solution is correct? Is there a better solution than my solution?
As far as I know, there is no other simple solution for detect calls' hang up.
There is an event PhoneCallManager.CallStateChanged, which can also detect hang up like below:
private bool callCame = false;
PhoneCallManager.CallStateChanged += PhoneCallManager_CallStateChanged;
private async void PhoneCallManager_CallStateChanged(object sender, object e)
{
if (callCame&&(!PhoneCallManager.IsCallActive))
{
//do something
}
if (PhoneCallManager.IsCallIncoming)
{
callCame = true;
}
}
But I don't think it's better than CallHistoryChanged trigger. And it won't get you the last Hang up phone's number either.
Is my solution is correct?
So yes, your solution is correct.
Update: There is no trick here. Register the BackgroundTask:
private void btnClick_Click(object sender, RoutedEventArgs e)
{
var taskRegistered = false;
var exampleTaskName = "MyBackgroundTask";
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == exampleTaskName)
{
taskRegistered = true;
break;
}
}
if (!taskRegistered)
{
var builder = new BackgroundTaskBuilder();
builder.Name = exampleTaskName;
builder.TaskEntryPoint = "PhoneCallBackground.Class1";
builder.SetTrigger(new PhoneTrigger(Windows.ApplicationModel.Calls.Background.PhoneTriggerType.CallHistoryChanged, false));
builder.Register();
}
}
And don't forget to register it in the appxmanifest file:
The Run Method will be fired after you hang up, if you registered the BackgroundTask. PhoneCallManager can not be registered for BackgroundTask. You need to set it as the default PhoneCall App, if you want to use this.
Update2:
I checked the demo, you are still using PhoneTriggerType.CallOriginDataRequest to register the background task. Please change it to PhoneTriggerType.CallHistoryChanged. And also make sure the registered background task is unregistered after you making any change to your codes.
Here is the demo that I modified: CallHistoryChangeTest.

Related

C# UWP, reusing geofences in geofencemonitor

I'm developing UWP app which will assist people with public transportation in my city. It uses geofencing to notify when the device is near some station. All is working fine, but slow. On my lumia 830 it took 4-5 seconds to prepare data for all 250 geofences and create them. Since, geofencemonitor runs under system and can store my geofences even when my app is terminated, I thought it would be smart to not recreate all geofences again and again on every app startup, but create them once and then just reuse them.
But I cant figure out how. When I start my app, Geofencemonitor.Current.Count is 250 and GeofenceMonitor.Current.Status is Ready, but it never fires Geoface state changed event.
My problem:
I m trying to reuse geofences in geofencemonitor. When I run my app and during startup I dont call Geofencemonitor.Current.Geofences.Clear(); and then create and add all my geofences -> geofence state change event is never fired.
Edit: It seems, that geofence status change fires only once after I add geofence to geofencemonitor, independently on if the app was restarted or not. But "used" geofence still remains in geofence monitor. Does geofence have some supended state? Am I missing some geofence property?
Here is how I create geofence:
var geofence = new Geofence(id, geocircle, mask, false, dwellTime);
GeofenceMonitor.Current.Geofences.Add(geofence);
My questions:
"Since, geofencemonitor runs under system and can store my geofences even when my app is terminated" - Is this really true?
If my first questions is true, and it is possible to reuse geofences, what am I doing wrong or do you know some place where I can go deeper into Geofencing in UWP?
Thanks for advice.
Here is how I listen geofences state change event:
ItsValueIs250 = Geofencemonitor.Current.Geofences.Count;
ItsValueIsReady = Geofencemonitor.Current.Status;
public async void OnGeofenceStateChanged(GeofenceMonitor sender, object e)
{
var reports = sender.ReadReports();
await Dispatcher.DispatchAsync( () =>
{
foreach (GeofenceStateChangeReport report in reports)
{
GeofenceState state = report.NewState;
Geofence geofence = report.Geofence;
if (state == GeofenceState.Entered)
{
stationInRange.Add(geofence.Id);
StationInRangeCount = stationInRange.Count().ToString();
}
else if (state == GeofenceState.Exited)
{
stationInRange.Remove(geofence.Id);
}
}
});
}
And maybe this method which I call during startup.
async public Task<string> GeomonitorInitialize()
{
string message = string.Empty;
var accessStatus = await Geolocator.RequestAccessAsync();
switch (accessStatus)
{
case GeolocationAccessStatus.Allowed:
int i = 0;
i = GeofenceMonitor.Current.Geofences.Count;
return message;
case GeolocationAccessStatus.Denied:
message = "GeoDenied";
return message;
case GeolocationAccessStatus.Unspecified:
message = "GeoError";
return message;
default:
message = "Default";
return message;
}
}
I will add any piece of code I use as you will wish. Thank you.

Windows Phone 8.1: Save list in app settings/storage

I just started developing a Windows Phone 8.1 app.
The app allows the user to add 'data' (strings) to his favorites-list.
Now the question is:
What is the best way to save the list or the single entries of the list so I am able load these favorites again on the next app start?
I thought I should save the data to a (text-) file so I can read it line by line and put the list together again.
What do you think, is this the best way to handle something like this? I am new to the Windows Phone 8.1 platform and any help is really appreciated - thanks!
The best method depends on size of data and your needs. As for saving it in Settings you can try to make an array of string upon save and make list upon loading data. Simple example can look like this:
List<string> favourites = new List<string>();
protected void Method()
{
// save as array
ApplicationData.Current.LocalSettings.Values["myList"] = favourites.ToArray();
// retrive your array and make a list from it
favourites = ((string[])ApplicationData.Current.LocalSettings.Values["myList"]).ToList();
}
Remember that LocalSettings support only simple types and have other limits - for more information take a look at MSDN.
I think i finally got it to work. Should thought about something like that much earlier.
So I got my async Task SaveAppSettingsAsync() and just call it in the Suspending-Event and in my Hardwarebuttons_Pressed-Event when the app closes:
private async void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
await SaveAppSettingsAsync();
deferral.Complete();
}
private async void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame != null)
{
e.Handled = true;
if (rootFrame.CurrentSourcePageType == typeof(MainPage))
{
await SaveAppSettingsAsync();
this.Exit();
}
else if (rootFrame.CanGoBack)
rootFrame.GoBack();
}
}
Thanks for helping. I think I got better at understanding how to handle async tasks now. As I said - I'm new to Windows Phone and never really used them before.

Windows Phone ContactPicker won't await properly

Although this has been posted before on StackOverflow but i think none of those reflect my issue and none of those solutions work for me either. So i'm developing a Windows Phone app and my workflow is a bit like this:
App starts
ContactPicker opens up
User selects one or multiple contacts
Based on how many contacts he selected, that many PivotItems are added into the Pivot.
My code is as follows:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// TODO: Prepare page for display here.
// TODO: If your application contains multiple pages, ensure that you are
// handling the hardware Back button by registering for the
// Windows.Phone.UI.Input.HardwareButtons.BackPressed event.
// If you are using the NavigationHelper provided by some templates,
// this event is handled for you.
SelectContacts();
}
private async Task SelectContacts()
{
var picker = new ContactPicker();
picker.DesiredFieldsWithContactFieldType.Add(ContactFieldType.PhoneNumber);
ContactsList = (List<Contact>)await picker.PickContactsAsync();
DisplayContacts();
}
private void DisplayContacts()
{
if (ContactsList != null)
{
foreach (var item in ContactsList)
{
PivotItem pivotItem = new PivotItem();
pivotItem.Header = item.FirstName.ToString();
ContentRoot.Items.Add(pivotItem);
}
}
}
According to me, in SelectContacts() method, the app should wait at the await call and once it gets back the list of contacts, than it should execute the DisplayContacts() method but its not working. I've tried multiple other variations of this code and they aren't working either.
await the SelectContacts() method and add the DisplayContacts() method beneath it. Remove the DisplayContacts() method from SelectContacts()
await SelectContacts();
DisplayContacts();
I don't know the complete reason why but i figured it out that since i was making the PickContactsAsync() call in the OnNavigatedTo() event, that is why it wasn't working as expected. Once i moved the PickContactsAsync() call into the PageLoaded() event handler, it started working as usual.

Issue with Async / Await method along with Choosers and Launchers

I added a the following extension method for photo chooser task and camera chooser task.
public static Task<TTaskEventArgs> ShowAsync<TTaskEventArgs>(this ChooserBase<TTaskEventArgs> chooser) where TTaskEventArgs : TaskEventArgs
{
var taskCompletionSource = new TaskCompletionSource<TTaskEventArgs>();
EventHandler<TTaskEventArgs> completed = null;
completed = (s, e) =>
{
chooser.Completed -= completed;
taskCompletionSource.SetResult(e);
};
chooser.Completed += completed;
chooser.Show();
return taskCompletionSource.Task;
}
And I invoked this method in my button click like this,
var photoResult = await new PhotoChooserTask().ShowAsync();
if (photoResult.TaskResult == TaskResult.OK)
{
// set the photo to image source.
}
After adding this every thing is working fine, But my issue is that while the time of invoking task by setting tombstone mode on, The code after my await is not executing (ie the completed event). How i can tackle this situation, I am expecting an answer that solve my issue on the above mentioned implementation(async / await). Not expecting the answer of registering event in the constructor.
I see you're following my article for this, it just turns out I forgot that my current solution doesn't work for tombstoning, as pointed out by someone in the article comments.
I'm preparing a fix for this, and I'll update the thread once I got it ready!

ExecuteAsync RestSharp to allow backgroundWorker CancellationPending c#

I'm new to C#, RestSharp, and threading, so heres what I'm trying to do:
I have made a program that will allow me to upload photos to tumblr, and I have the uploading working so far. Now I need the stop button to work, which I believe means I must use ExecuteAsync() instead of Execute().
I also have my code put in a backgroundworker, like this:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
MessageBox.Show("You pressed Cancel.");
}
else
{
var restClient = new RestClient("http://tumblr.com/api/write");
foreach (string item in queueBox.Items)
{
var request = new RestRequest(Method.POST);
request.RequestFormat = DataFormat.Json; //I don't know if this line is necessary
request.AddParameter("email", usernameBox.Text);
request.AddParameter("password", passwordBox.Text);
request.AddParameter("type", "photo");
request.AddFile("data", FolderName + "\\" + item);
RestResponse response = restClient.Execute(request);
doneBox.Invoke(new UpdateTextCallback(this.UpdateText),
new object[] { item });
}
}
}
I believe I have set this up correctly. When I press upload it goes to else accordingly. However, I think that RestResponse response = restClient.Execute(request); this is blocking, which isn't allowing my code to continue checking the flag.
This is how I attempt to cancel it.
public void stopButton_Click(object sender, EventArgs e)
{
doneBox.Items.Add("You pressed the stop button.");
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.CancelAsync();
}
Also, incase this is relevant, I have:
public delegate void UpdateTextCallback(string item); which allows me to call UpdateText and FinishedText as seen above in backgroundWorker1_DoWork.
For my question, how can I use ExecuteAsync in this context? I have searched but I cannot find anything that will help me, I can't find an example that is similar to my code, and since I'm new to c# I am unable to convert it to what I want.
And also, I am open to suggestions, if you see some inefficiency in my code or what not, I will be happy to accept your suggestions.
Thank you.
There are a couple of potential problems here.
First, you seem to be trying to access a UI element from your background thread (as well open a MessageBox). This has a potential of throwing a CrossThread exception*.
Second, your code should look more like this:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var restClient = new RestClient("http://tumblr.com/api/write");
foreach (string item in queueBox.Items)
{
//This should be inside the foreach
//as it is your loop that will check for cancel.
//Your code is procedural once it is in the backgroundworker
//so it would never return to the spot you had it
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
//MessageBox.Show("You pressed Cancel.");
//Removed this to the background worker completed method below
//This avoids any UI cross thread exceptions
return;
}
var request = new RestRequest(Method.POST);
//I believe Json is default for Restsharp, but you would have to play with it
request.RequestFormat = DataFormat.Json; //I don't know if this line is necessary
request.AddParameter("email", usernameBox.Text);
request.AddParameter("password", passwordBox.Text);
request.AddParameter("type", "photo");
request.AddFile("data", FolderName + "\\" + item);
//If you just pass in item to the below Func, it will be a closure
//Meaning, any updates in the loop will propogate into the Action
var newItemToAvoidClosure = item;
//To use Async, you set up the callback method via a delegate
//An anonymous method is as good as any here
restClient.ExecuteAsync(request,
response=>
{
//Maybe you should do something with the response?
//Check the status code maybe?
doneBox.Invoke(new UpdateTextCallback(this.UpdateText),
new object[] { newItemToAvoidClosure });
}
);
}
}
Wire your background worker's RunWorkerCompleted method to this and perform all of your post processing here:
private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if(e.Cancelled)
MessageBox.Show("You pressed Cancel"
}
Also, if you are using 4.0+, then I suggest looking into the Task Parallel Library. It can make your code much cleaner IMO :).
Finally, a note about the above code, what will happen is that the background worker has a high potential to return completed before all of the Rest calls complete. This will probably run fairly quick, and leave the calls still to continue as they are not cancellable in this fashion (the background worker will have already completed)(but I believe there is a way to do this for each Rest call). So, it seems to me that the real problem was that the cancellation check was in the wrong part of the code (notice I moved it inside the loop, so that it can be checked after each file was processed). You are already running in a background thread, so it seems to me that there is no point to calling another async (unless your intent is to offload the looping of the data to be sent, which then offloads the actual sending).
So, in conclusion. I provided the way to call the async, but I believe the bigger problem was that you were not checking for the cancel call appropriately.
*It may not since you are only accessing and not updating the UI element, and you did say this part was working (it probably will for the MessageBox, though)

Categories