Android Activity destroyed when calling ZXing barcode scanner. How to recover? - c#

First of all, I'm using, Xamarin with MvvmCross.
In my ViewModel, I'm using the ZXing MobileBarcodeScanner class to scan a barcode when the user clicks a button:
var scanner = new MobileBarcodeScanner();
var result = await scanner.Scan();
if (result != null)
{
CodigoProduto = result.Text;
InternalPesquisarProduto();
}
After the scan, I run the InternalPesquisarProduto void, that search for data on a remote server, based of course, on the barcode that was read. This method, also display some loading message while the data is fetched:
Ui.DisplayLoading("Searching...", "Searching data");
// Code that fetches the data
Ui.DismissLoading();
The Ui is a property on my ViewModel defined like this:
protected IUiInteractor Ui { get; set; }
I receive it by dependency injection. Here is the relevant code from the implementation being used in this scenario:
public class AndroidUiInteractor : IUiInteractor
{
private IMvxAndroidCurrentTopActivity _mvxCurrentTopActivity;
public AndroidUiInteractor(IMvxAndroidCurrentTopActivity mvxCurrentTopActivity)
{
_mvxCurrentTopActivity = mvxCurrentTopActivity;
}
public void DisplayLoading(string title, string message)
{
_mvxCurrentTopActivity.Activity.RunOnUiThread(() =>
{
_progressDlg = new ProgressDialog(_mvxCurrentTopActivity.Activity);
// Configuring the title and the message
_progressDlg.Show();
});
}
}
The problem is that when the scanner.Scan is called, my caller activity is destroyed, so when I call the Ui.DisplayLoading, the _mvxCurrentTopActivity.Activity is null.
What is most weird about this case, is that I have two Samsungs with Android 5.0 API 21 that I use in my tests, and this problem only happens in one of them, on the other, the activity is not destroyed when calling the scanner.Scan.
Note: I'm sorry for anything wrong in the code, but because of company policies, I can only access the internet by Terminal Service, and the Ctrl + V is disabled on it.

It turns out the problem was in the device. After reseting it's configurations it worked properly.
This might not be a definitive solution for everyone that faces that problem, but in my scenario it could be done.

Related

How to read or control a pin from different thread in C# and Raspberry Pi

I have a C# WebAPI application running on Raspberry Pi that controls a water valve. I want to be able to open the valve for 60 minutes on one thread and check the state on a separate thread. I have separate threads for opening the valve and checking the state which work correctly on their own. The problem I'm having is the thread for checking the state doesn't read the correct value until the original open thread is finished.
How can I read or control a pin from a different thread?
Also, I'm using the System.Device.Gpio library.
This is the code I have.
...
using System.Device.Gpio;
...
[ApiController]
[Route("[controller]")]
public class WaterValveSensorController : ControllerBase
{
private GpioController controller = new GpioController();
[HttpGet("{gpioPin}")]
public WaterValveReading Get(int gpioPin)
{
//This method is intended for adhoc requests to get the status of the watervalve whether the valve is open or closed.
var valveOpen = IsPinOpen(gpioPin);
var waterValveReading = new WaterValveReading(microComputer.HostName, microComputer.IP, gpioPin, valveOpen, DateTimeOffset.Now);
return waterValveReading;
}
[Route("[action]/{gpioPin}/{wateringSeconds}")]
[HttpGet]
public async Task StartWatering(int gpioPin, int wateringSeconds)
{
var maxWateringSeconds = int.Parse(configuration["WaterValveSettings:MaxWateringSeconds"]);
if (OpenValve(gpioPin))
{
await Task.Delay(TimeSpan.FromSeconds((wateringSeconds > maxWateringSeconds) ? maxWateringSeconds : wateringSeconds));
}
}
private bool OpenValve(int gpioPin)
{
if (!IsPinOpen(gpioPin))
{
controller.OpenPin(gpioPin, PinMode.Output);
controller.Write(gpioPin, PinValue.High);
}
return true;
}
private bool IsPinOpen(int gpioPin)
{
return controller.IsPinOpen(gpioPin);
}
}
I think your Get function mixes up a few things. IsPinOpen asks whether the pin has been opened for reading/writing. It does not indicate whether the valve is open or not. Therefore using it to construct the WaterValveReading structure is quite pointless. Additionally, you need to be aware that the GpioController class is not currently thread safe, so opening/closing pins from different threads is dangerous (reading/writing the pin value should be safe, though).
[HttpGet("{gpioPin}")]
public WaterValveReading Get(int gpioPin)
{
//This method is intended for adhoc requests to get the status of the watervalve whether the valve is open or closed.
bool valvePinOpen = IsPinOpen(gpioPin);
WaterValveReading waterValveReading;
if (valvePinOpen)
{
var isValveOpen = controller.Read(gpioPin);
waterValveReading = new WaterValveReading(microComputer.HostName, microComputer.IP, gpioPin, isValveOpen, DateTimeOffset.Now);
}
else
{
waterValveReading = new WaterValveReading(....); // Some error return (pin not open)
}
return waterValveReading;
}
Additionally, I would reconsider whether you want the pin number to be in the web request. Typically, that will be fixed by hardware (the valve is attached to a very specific pin), so that having it in the API would allow the caller to open and write any pin, with possibly undesired side effects. If you know the pin number beforehand, you can open the corresponding pin already in the constructor.

Why is the hub context connection ID inaccessible at runtime in my VERY simple method?

Let me start by saying this all works perfectly at the moment except for one thing - the notification update for the progress bar goes to all clients (as you would expect given that the code example I used sends to ...Clients.All).
All I want to do is send the notification back to the client that initiated the current call to the hub. That's it, nothing else. There is no concept of "logging in" on this website so there's no user identity stuff to work with.
My method is:
public void NotifyUpdates(decimal val)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<EventsForceHub>();
if (hubContext != null)
{
//"updateProgress" is javascript event trigger name
await hubContext.Clients.All.updateProgress(val);
}
}
So back in my view I subscribe to "updateProgress" and it works fine - the progress bar updates as desired. But if another client happens to be connected to the hub, when one runs the async task and causes the NotifyUpdates method to run, then ALL connected clients see the taskbar update, which is a bit confusing for them!
In debug, if I inspect hubContext at runtime I can see a Clients property and that has a Connection property which has an Identity property with a unique GUID. Perfect! Just what I want to use. But... I cannot access it! If I try:
var currentConnection = hubContext.Clients.Connection;
...then I simply get a
"does not contain a definition for 'Connection'"
error, which I simply don't understand.
I've tried accessing Context.ConnectionId from the method too, but Context is null at that point so I'm a bit confused. The server method that uses NotifyUpdates to send information back to the client is called via a normal asp.net button, not via AJAX.
Clarification on structure
I think there is a degree of confusion here. It's a very simply webpage with an asp.net button control on it. The eventhandler for that button invokes an async method to return data from the server via a service call/repository.
Inside the async method, it has to process each returned data line and make three or four remote web api calls. On each loop I make a call back to the NotifyUpdates SignalR method shown above with a percentage complete number so this can update back to the client via an eventhandler for the method name specified (updateProgress as shown above). There could be dozens of data lines and each data line requires several Web API calls to a remote server to add data. This can take several seconds per iteration, hence me sending back the "update progress" to the client via that updateProgress method call.
NEW ANSWER
Based on your comments I made the following little test:
It will allow clients to connect to the hub with a clientName, and every client is listening to updates send to them. We will have a group defined for them to be able to notify them from the server side.
I made a dummy progress simulator class to throw some update values to the users.
The code:
Hub class:
public class EventsForceHub : Hub {
public static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<EventsForceHub>();
// allow users to join to hub and get s dedicated group/channel for them, so we can update them
public async Task JoinGroup(string clientName) {
string clientID = Context.ConnectionId;
ClientInfo.clients.Add(clientID, new MyAppClient(clientID, clientName));
await Groups.Add(clientID, clientName);
// this is just mockup to simulate progress events (this uis not needed in real application)
MockupProgressGenerator.DoJob(clientName, 0);
}
public static void NotifyUpdates(decimal val, string clientName) {
// update the given client on his group/channel
hubContext.Clients.Group(clientName).updateProgress(val);
}
}
Some little helper classes:
// client "storage"
public static class ClientInfo {
public static Dictionary<string, MyAppClient> clients = new Dictionary<string, MyAppClient>();
// .. further data and methods
}
// client type
public class MyAppClient {
public string Id { get; set; }
public string Name { get; set; }
// .. further prooerties and methods
public MyAppClient(string id, string name) {
Id = id;
Name = name;
}
}
// this a completely made up and dumb class to simulate slow process and give some simple progress events
public static class MockupProgressGenerator {
public static void DoJob(string clientName, int status) {
if (status < 100) {
Task.Delay(1000).ContinueWith(a =>
{
EventsForceHub.NotifyUpdates(status += 20, clientName);
DoJob(clientName, status);
});
}
}
}
Let's see two simple clients in JS:
$(function () {
var eventsForceHub = $.connection.eventsForceHub;
$.connection.hub.start().done(function () {
$('body').append("Joining with Name: Jerry");
eventsForceHub.server.joinGroup("Jerry");
});
eventsForceHub.client.updateProgress = function (val) {
// message received
$('body').append('<br>').append("New Progress message: " + val);
};
});
For simplicity, same code, with different params, I even put this in two different html pages and stated execution in slightly different timing.
$(function () {
var eventsForceHub = $.connection.eventsForceHub;
$.connection.hub.start().done(function () {
$('body').append("Joining with Name: Tom");
eventsForceHub.server.joinGroup("Tom");
});
eventsForceHub.client.updateProgress = function (val) {
// message received
$('body').append('<br>').append("New Progress message: " + val);
};
});
See it in action:
FIRST ANSWER
I made a small web application to verify your claim. You may create the following to be able to isolate the issue from other possible problems.
I created an empty Web Application and included SignalR.
This is the hub class:
public class EventsForceHub : Hub {
public void NotifyUpdates(decimal val) {
var hubContext = GlobalHost.ConnectionManager.GetHubContext<EventsForceHub>();
if (Context != null) {
string clientID = Context.ConnectionId; // <-- on debug: Ok has conn id.
object caller = Clients.Caller; // <-- on debug: Ok, not null
object caller2 = Clients.Client(clientID); // <-- on debug: Ok, not null
Clients.Caller.updateProgress(val); // Message sent
Clients.Client(clientID).updateProgress(val); // Message sent
}
if (hubContext != null) {
//"updateProgress" is javascript event trigger name
hubContext.Clients.All.updateProgress(val); // Message sent
}
}
}
This is the web page:
<script src="Scripts/jquery-1.10.2.min.js"></script>
<script src="Scripts/jquery.signalR-2.2.2.min.js"></script>
<script src="signalr/hubs"></script>
<script type="text/javascript">
$(function () {
var eventsForceHub = $.connection.eventsForceHub;
$.connection.hub.start().done(function () {
// send mock message on start
console.log("Sending mock message: " + 42);
eventsForceHub.server.notifyUpdates(42);
});
eventsForceHub.client.updateProgress = function (val) {
// message received
console.log("New Progress message: " + val);
};
});
</script>
Try to build an application as little as this to isolate the issue. I have not had any of the issues you mentioned.
For the sake of simplicity and using the debugger I took away the await and async.
Actually, SignalR will take care of that for you. You will get a new instance of your Hub class at every request, no need to force asynchrony into the methods.
Also, GlobalHost is defined as static which should be shared between instances of your Hub class. Using in an instance method does not seem like a very good idea. I think you want to use the Context and the Clients objects instead. However, while debugging we can verify that using GlobalHost also works.
Some debugger screenshots showing runtime values of callerId, Clients.Caller and Clients.Client(clientID):
Understanding SignalR better will help you a lot in achieving your goal.
Happy debugging!
If you want to send the notification back to the client
you should not call
hubContext.Clients.All.updateProgress(val);
instead try
accessing the current user's ConnectionId and use Clients.Client
hubContext.Clients.Client(Context.ConnectionId);

WP8.1 Silverlight - Unexpected License info on LicenseChanged

I am trying to detect In-App-Purchases made by a client app.
I am using the following code
public async Task InitializeInAppPurchase()
{
CurrentApp.LicenseInformation.LicenseChanged += LicenseInformation_LicenseChanged;
var listingInformationTask = CurrentApp.LoadListingInformationAsync();
var listingInformation = await listingInformationTask;
PurchaseProduct(listingInformation.ProductListings.First().Value.ProductId);
}
private void LicenseInformation_LicenseChanged()
{
var receipt = CurrentApp.GetAppReceiptAsync().AsTask().Result;
Console.Writeline(receipt);
}
async void PurchaseProduct(string productId)
{
try
{
// Kick off purchase; don't ask for a receipt when it returns
var result = await CurrentApp.RequestProductPurchaseAsync(productId);
// Now that purchase is done, give the user the goods they paid for
// (DoFulfillment is defined later)
await DoFulfillment(result);
}
catch (Exception ex)
{
// When the user does not complete the purchase (e.g. cancels or navigates back from the Purchase Page), an exception with an HRESULT of E_FAIL is expected.
}
}
//
// Fulfillment of consumable in-app products
public async Task DoFulfillment(PurchaseResults result)
{
var productLicenses = CurrentApp.LicenseInformation.ProductLicenses;
// Check fulfillment for consumable products with hard-coded asset counts
await MaybeGiveMeGold(productLicenses["Test1"], 50, result);
}
// Count is passed in as a parameter
async Task MaybeGiveMeGold(ProductLicense license, int goldCount, PurchaseResults result)
{
if (license.IsConsumable && license.IsActive)
{
await CurrentApp.ReportConsumableFulfillmentAsync(license.ProductId, result.TransactionId);
}
}
When the event LicenseChanged is raised, I am surprised to see that the receipt does not include the transaction which just occurred. I get this
<Receipt Version="1.0" ReceiptDate="2015-06-18T04:41:31.867Z" ReceiptDeviceId="4e362949-acc3-fe3a-e71b-89893eb4f528" CertificateId="FB3D3A6455095D2C4A841AA8B8E20661B10A6112" xmlns="http://schemas.microsoft.com/windows/2012/store/receipt">
<AppReceipt Id="8ffa256d-eca8-712a-7cf8-cbf5522df24b" AppId="01e34c43-fdd8-47a6-a8ba-36ad5b880de9" PurchaseDate="2015-06-18T04:41:31.867Z" LicenseType="Full" />
</Receipt>
whereas the receipt should include a element as documented here
I am using the emulator and I am also using a mock server hosted locally in IIS to return my fake ProductListings from here
Can anyone tell me if there is something that I am doing wrong or if this simply what has been designed by Microsoft?
I know that In App Purchases behave differently on emulators, does anyone know if I would have had the expected behavior if I were using a real device?
Thank you
That behavior was normal because the Marketplace mock hosted locally could not return receipts for any transactions.
To test my In-App-Purchases, I had to
Publish my app in beta mode
Create test IAPs at 0.00$
The code above worked perfectly and the LicenseChanged events is raised almost instantaneously depending on network conditions.

Using the Lync 2013 SDK in a multithreaded application

I want to use the Lync 2013 SDK in a WPF application to query contact availability, although I’m seeing some strange behaviour. I suspect this is because of the way I am calling it from many threads at a time, although not sure of the best approach to resolve this.
I have a custom UserControl for displaying contact information for people within our company. I load a collection of these controls into a single form based on a search query. Each contact control will load detailed information about the contact on creation, using the ThreadPool to apply some throttling. All information up until this point is coming from AD, which has been working well.
Now I want to show the contact availability status of each contact. I have put together this code, which has been modified from another post.
private LyncClient _lyncClient;
private ContactSubscription _contactSubscription;
private void GetContactAvailability(string sip)
{
if (!String.IsNullOrEmpty(sip))
{
_lyncClient = LyncClient.GetClient();
if (_lyncClient.State == ClientState.SignedIn)
{
_lyncClient.ContactManager.BeginSearch(
sip,
SearchProviders.Default,
SearchFields.EmailAddresses,
SearchOptions.ContactsOnly,
1,
BeginSearchCallback,
new object[] {_lyncClient.ContactManager, sip});
}
}
}
private void BeginSearchCallback(IAsyncResult r)
{
var asyncState = (object[]) r.AsyncState;
var cm = (ContactManager) asyncState[0];
var results = cm.EndSearch(r);
if (results.AllResults.Count > 0)
{
Debug.WriteLine(results.Contacts.Count);
Microsoft.Lync.Model.Contact contact = results.Contacts[0];
UpdateLyncStatus(contact);
_contactSubscription = cm.CreateSubscription();
_contactSubscription.AddContact(contact);
contact.ContactInformationChanged += contact_ContactInformationChanged;
ContactInformationType[] contactInformationTypes = {ContactInformationType.Availability};
_contactSubscription.Subscribe(ContactSubscriptionRefreshRate.High, contactInformationTypes);
}
}
private void contact_ContactInformationChanged(object sender, ContactInformationChangedEventArgs e)
{
var contact = (Microsoft.Lync.Model.Contact) sender;
UpdateLyncStatus(contact);
}
private void UpdateLyncStatus(Microsoft.Lync.Model.Contact contact)
{
if ((_lyncClient != null) && (_lyncClient.State == ClientState.SignedIn))
{
UpdateLyncStatus((ContactAvailability) contact.GetContactInformation(ContactInformationType.Availability));
}
}
If my search form returns only a single result, then this code seems to work every time to successfully return the availability status for a single contact control. If I do a more generic search, such as “John” (which returns 50+ results), only a few (if any) of the contacts show the availability status. The code doesn’t generate any exceptions, it just doesn’t work.
If I repeat the search for “John” again, then all of the contacts will show an availability status. I suspect these statuses are cached from the previous Lync search, which is great, but how do I get them to show in the first search?
Is there a better way to use the Lync SDK in a multithreaded application?

Handling Windows App Store In-app purchase receipt

I would like to handle situation in such case, user performs purchasing in this machine, but which to run the feature in another machine.
I know I have to check for receipt. I was wondering, is this the correct way to do so? Note that, I bypass signature check. As, I need to setup a backend system which I do not want to consider at this moment. I can't even perform signature check locally, as Windows 8 Store App doesn't provide System.Security.Cryptography API.
I was wondering, whether the following code snippet is good enough to handle most of the cases? Note, I unable to test the code, as I need to publish a new version, in order for me to test the code.
private async void history_Click(object sender, RoutedEventArgs e)
{
bool OK = true;
// The next line is commented out for production/release.
LicenseInformation licenseInformation = CurrentApp.LicenseInformation;
if (!licenseInformation.ProductLicenses["PremiumFeatures"].IsActive)
{
try
{
// The customer doesn't own this feature, so
// show the purchase dialog.
String receipt = await CurrentApp.RequestProductPurchaseAsync("PremiumFeatures", true);
// the in-app purchase was successful
licenseInformation = CurrentApp.LicenseInformation;
if (licenseInformation.ProductLicenses["PremiumFeatures"].IsActive || receipt.Length > 0)
{
// In some situations, you may need to verify that a user made an in-app purchase.
// For example, imagine a game that offers downloaded content. If the user who
// purchased the content wants to play the game on another PC, you need to verify
// that the user purchased the content.
//
// Receipt is used to handle such situation.
//
// Validate receipt is complicated, as it requires us to setup a backend system.
// http://msdn.microsoft.com/en-US/library/windows/apps/jj649137
//
// I will just assume non empty receipt string means valid receipt.
OK = true;
}
else
{
OK = false;
}
}
catch (Exception)
{
// The in-app purchase was not completed because
// an error occurred.
OK = false;
}
}
else
{
// The customer already owns this feature.
OK = true;
}
if (OK)
{
// Launch premium feature.
Frame.Navigate(typeof(HistoryPage));
}
}
You can test your code using CurrentAppSimulator instead of CurrentApp. It looks ok to me.

Categories

Resources