Skip to content
This repository has been archived by the owner on Dec 3, 2024. It is now read-only.

Android: StartAsync resolves too fast #70

Open
nc-kano opened this issue Jun 2, 2020 · 10 comments
Open

Android: StartAsync resolves too fast #70

nc-kano opened this issue Jun 2, 2020 · 10 comments

Comments

@nc-kano
Copy link

nc-kano commented Jun 2, 2020

When we run StartAsync method with bluetooth OFF it correctly shows us a dialog and after clicking ok it turns the BT on. However if we check status right after that with GetStatusAsync() it returns BluetoothOff as adapter haven't manage it to start fast enough. Because of that we need to start again so we see the dialog for the second time.
I think the StartAsync should wait until adapter will be enabled and then resolve.

Issue observed on Xiaomi Redmi Note 8T with Android 9 and Huawei Mate 20 lite with Android 10

@nc-kano
Copy link
Author

nc-kano commented Jun 22, 2020

Update:
I have investigated it further and I have found a differences in start method for Xamarin and android:
android solution:

start()
        .addOnSuccessListener(
            unused -> {
            })
        .addOnFailureListener(
            exception -> {
            })
       .addOnCanceledListener(() -> {});

Xamarin:
await StartAsync(); // returns only empty Task

So the android solution gives us more information here.

Also I have found a workaround for this issue:
If we will create a BroadcastReceiver for bluetooth adapter ("android.bluetooth.adapter.action.STATE_CHANGED") and await for the bluetooth to turn on in OnActivityResult method before we will call ExposureNotification.OnActivityResult(requestCode, resultCode, data) it will work correctly.

@nc-kano
Copy link
Author

nc-kano commented Jun 22, 2020

My simplified workaround:

        public static TaskCompletionSource<bool> AgBluetoothTaskCompletionSource;

        public async void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            if (requestCode != EnApiRequestCode || resultCode != Result.Ok) return;
            AgBluetoothTaskCompletionSource = new TaskCompletionSource<bool>();
            if (BluetoothAdapter.DefaultAdapter != null
                && BluetoothAdapter.DefaultAdapter.IsEnabled)
            {
                AgBluetoothTaskCompletionSource.TrySetResult(true);
            }
            // Set timeout
            Task.Run(async () =>
            {
                await Task.Delay(Timeout);
                AgBluetoothTaskCompletionSource?.TrySetResult(BluetoothAdapter.DefaultAdapter != null
                                                              && BluetoothAdapter.DefaultAdapter.IsEnabled);
            });

            await AgBluetoothTaskCompletionSource.Task;

            ExposureNotification.OnActivityResult(requestCode, resultCode, data);
        }

where AgBluetoothTaskCompletionSource is set to true in broadcast receiver when bluetooth is ON

@mattleibow
Copy link
Contributor

@nc-kano I looked into this and I am not sure exactly why yours is returning too soon. Have you tested the code on Android and confirmed that it does actually wait?

Looking at our code, we also wait the Android task: https://github.com/xamarin/XamarinComponents/blob/master/XPlat/ExposureNotification/source/Xamarin.ExposureNotification/ExposureNotification.android.cs#L100

The chain from native code to the xplat is basically: start the Android task, convert it to a .NET task, await the .NET task. The only way for the .NET task to finish is to wait for the Android task to complete.

I'll do some tests with my device and see exactly what is happening. Maybe we missed something, maybe the Android SDK has an issue.

@nc-kano
Copy link
Author

nc-kano commented Jun 22, 2020

@mattleibow Thank you for the response.
Yes, I have tested it. Until now it was tested on a wide variety of devices and on all it behaves in the similar way.

Our starting method is more or less like this:

        public async Task<bool> StartBluetooth()
        {
            try
            {
                await Xamarin.ExposureNotifications.ExposureNotification.StartAsync();
            }
            catch (Exception e)
            {
                // Error handling
            }
            return (await Xamarin.ExposureNotifications.ExposureNotification.GetStatusAsync() == Status.Active);
        }

And it always return false if bluetooth was turned off.

@JanettHolst290490
Copy link

I hope you have time to look at this soon. We have this issue in production with half a million users.

@dlandi
Copy link

dlandi commented Jul 18, 2020

Hi. So what is the general consensus on this app/library. Is it now stable enough to use in production?

I've been holding off on implementation until the debugging/refactoring has settled down, and it seems to have at this point.

Anyone using this in production?

@nc-kano
Copy link
Author

nc-kano commented Aug 6, 2020

@dlandi yes, we are using it in Denmark. Despite this issue with starting API is working fine.

@nc-kano
Copy link
Author

nc-kano commented Aug 6, 2020

@mattleibow xamarin sample application does not work at all as it is even not on a list of covid tracking apps. it is installed and enabled but android does not recognize it as covid tracking app and when we enable exposure notifications in the app there is no system dialog:
image
so it cannot be treated as a reference for starting of the app.

@cris-m
Copy link

cris-m commented Aug 6, 2020

@mattleibow Thank you for the response.
Yes, I have tested it. Until now it was tested on a wide variety of devices and on all it behaves in the similar way.

Our starting method is more or less like this:

        public async Task<bool> StartBluetooth()
        {
            try
            {
                await Xamarin.ExposureNotifications.ExposureNotification.StartAsync();
            }
            catch (Exception e)
            {
                // Error handling
            }
            return (await Xamarin.ExposureNotifications.ExposureNotification.GetStatusAsync() == Status.Active);
        }

And it always return false if bluetooth was turned off.

I have try this on Samsung A20 SC-02M and it doenot start the Exposure notification API

@JanettHolst290490
Copy link

So do you confirm that there is a bug?
No it will not start the EN Api before you accept the permission popup.

We would expect StartAsync to not resolve the task before it is in fact started and GetStatusAsync will return Status.Active.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants