dpa99c / cordova-diagnostic-plugin

Cordova/Phonegap plugin to manage device settings
540 stars 361 forks source link

Weird getMotionAuthorizationStatus() behaviour on iPad #372

Closed fcamblor closed 5 years ago

fcamblor commented 5 years ago

I'm submitting a ... (check one with "x"):

Bug report

Current behavior: On iPad Mini 4, when I call getMotionAuthorizationStatus(), I always get a not_requested outcome, even when I call requestMotionAuthorization() prior to it (no matter what I respond to the motion authorization request popup).

eg :

cordova.plugins.diagnostic.getMotionAuthorizationStatus(motionStatus => {
    console.log("fist motion authorization status : "+JSON.stringify(motionStatus));
    cordova.plugins.diagnostic.requestMotionAuthorization(requestedMotionStatus => {
        console.log("first request motion authorization outcome : "+JSON.stringify(requestedMotionStatus));
        cordova.plugins.diagnostic.getMotionAuthorizationStatus(motionStatus2 => {
            console.log("second motion authorization status : "+JSON.stringify(motionStatus2));
            cordova.plugins.diagnostic.requestMotionAuthorization(requestedMotionStatus2 => {
                console.log("second request motion authorization outcome : "+JSON.stringify(requestedMotionStatus2));
            }, console.error);
        }, console.error);
    }, console.error);
}, console.error);

outputs :

[Log] fist motion authorization status : "not_requested" (t.js, line 13)
// Motion authorization request popup opened ... same logs below wether I allow or deny the motion authorization...
[Log] first request motion authorization outcome : "not_determined" (t.js, line 13)
[Log] second motion authorization status : "not_requested" (t.js, line 13)
[Log] second request motion authorization outcome : "not_determined" (t.js, line 13)

Expected behavior:

I understand that iPad motion is half available (we can request it, but since we don't have Pedometer events on iPads, it cannot be determined)

However, I would have expected that a second call (after requestMotionAuthorization() call) to getMotionAuthorizationStatus() would return not_determined instead of not_requested

WDYT about my assumption ?

Current behaviour is annoying because I need to always rely on requestMotionAuthorization() to have a "true" status, since getMotionAuthorizationStatus() doesn't give me the true status on iPad.

Steps to reproduce:

Execute following code :

cordova.plugins.diagnostic.getMotionAuthorizationStatus(motionStatus => {
    console.log("fist motion authorization status : "+JSON.stringify(motionStatus));
    cordova.plugins.diagnostic.requestMotionAuthorization(requestedMotionStatus => {
        console.log("first request motion authorization outcome : "+JSON.stringify(requestedMotionStatus));
        cordova.plugins.diagnostic.getMotionAuthorizationStatus(motionStatus2 => {
            console.log("second motion authorization status : "+JSON.stringify(motionStatus2));
            cordova.plugins.diagnostic.requestMotionAuthorization(requestedMotionStatus2 => {
                console.log("second request motion authorization outcome : "+JSON.stringify(requestedMotionStatus2));
            }, console.error);
        }, console.error);
    }, console.error);
}, console.error);

My assumption would be to have this output :

[Log] fist motion authorization status : "not_requested" (t.js, line 13)
// Motion authorization request popup opened ... same logs below wether I allow or deny the motion authorization...
[Log] first request motion authorization outcome : "not_determined" (t.js, line 13)
[Log] second motion authorization status : "not_determined" (t.js, line 13)
[Log] second request motion authorization outcome : "not_determined" (t.js, line 13)

Environment information

Runtime issue

Related code:

cordova.plugins.diagnostic.getMotionAuthorizationStatus(motionStatus => {
    console.log("fist motion authorization status : "+JSON.stringify(motionStatus));
    cordova.plugins.diagnostic.requestMotionAuthorization(requestedMotionStatus => {
        console.log("first request motion authorization outcome : "+JSON.stringify(requestedMotionStatus));
        cordova.plugins.diagnostic.getMotionAuthorizationStatus(motionStatus2 => {
            console.log("second motion authorization status : "+JSON.stringify(motionStatus2));
            cordova.plugins.diagnostic.requestMotionAuthorization(requestedMotionStatus2 => {
                console.log("second request motion authorization outcome : "+JSON.stringify(requestedMotionStatus2));
            }, console.error);
        }, console.error);
    }, console.error);
}, console.error);

Kind regards,

dpa99c commented 5 years ago

This has been fixed in v5.0.1

fcamblor commented 5 years ago

@dpa99c for my knowledge, can you confirm you just disabled availability of motion permission on the iPad mini 4 model device prior to v5.0.1 ?

WARNING : message below is not right as I was testing on an iPad Mini 1 instead of an iPad mini 4 (see https://github.com/dpa99c/cordova-diagnostic-plugin/issues/372#issuecomment-537021645)

As I can see changes in behaviour between 4.0.12 and 5.0.1 for the iPad Mini 4 :

Version isMotionRequestOutcomeAvailable() requestMotionAuthorization() behaviour requestMotionAuthorization() outcome getMotionAuthorizationStatus() outcome
v4.0.12 true shows permission popup once always not_determined even when choice has been made in the permission popup always not_requested, even after permission popup being shown
v5.0.1 false nothing always not_available always not_requested

(note that I'm not against this change, but I'm trying to understand the implications of this change here :-) )

dpa99c commented 5 years ago

I'm testing v5.0.1 on an iPad Air 2 running iOS 12.4 using the example project (by inserting plugin calls directly into the Webview via Safari Web Inspector) and the results I see are this:

  1. cordova.plugins.diagnostic.isMotionRequestOutcomeAvailable(result => console.log(result)) => false
  2. cordova.plugins.diagnostic.getMotionAuthorizationStatus(result => console.log(result)) => not_requested
  3. cordova.plugins.diagnostic.requestMotionAuthorization(result => console.log(result)) => (shows permission dialog) => press "OK" or "Don't Allow" => not_determined
  4. cordova.plugins.diagnostic.getMotionAuthorizationStatus(result => console.log(result)) => not_determined

These are the results I would expect.

Can you try the same set of commands on your iPad Mini 4 and see if you get the same results?

fcamblor commented 5 years ago

Hi @dpa99c,

You can see the outcome of those in my table previously.

Anyway, it was not on your sample app, so just in case I tried with your sample app but had exactly the same results as those described in the table above (not permission popup when calling requeastMotionAuthorization()) : Cordova_diagnostic_issue_on_iPad_Mini_4

dpa99c commented 5 years ago

The results on your iPad Mini 4 indicate that the CoreMotion APIs are responding differently than to my iPad Air 2. Unfortunately I don't have a physical iPad running iOS 10 so I can't debug this in Xcode to explain why this is (iOS Simulator doesn't support CoreMotion APIs).

Therefore, if you want to investigate this further, you'll need to debug on the device in Xcode yourself. I suggest setting breakpoints in Diagnostic_Motion.m at line 92, and line 96 when calling requestMotionAuthorization() to see if iOS enters that completion block with no permission popup.

And also at line 51 to check if the motion_permission_requested flag is nil when subsequently calling getMotionAuthorizationStatus().

If you have an iPad running a newer version of iOS, you can repeat the tests to see if the results are different.

fcamblor commented 5 years ago

And also at line 51 to check if the motion_permission_requested flag is nil when subsequently calling getMotionAuthorizationStatus().

Yes, motion_permission_requested is nil Diagnostic_-_Motion_permission_requested_being_nil

Therefore, if you want to investigate this further, you'll need to debug on the device in Xcode yourself. I suggest setting breakpoints in Diagnostic_Motion.m at line 92, and line 96 when calling requestMotionAuthorization() to see if iOS enters that completion block with no permission popup.

As stated above, isMotionRequestOutcomeAvailable() is returning false And while in debug, I never stop at lines 92 & 96 because [self isMotionAvailable] statement returns nil

dpa99c commented 5 years ago

OK, now I see what's going on: CoreMotion is not available on your iPad Mini 4 (there must be no motion co-processor onboard) so isMotionAvailable is false. Therefore, the motion_permission_requested flag is never set so getMotionAuthorizationStatus always returns not_requested.

I can fix this by adding a check for isMotionAvailable in getMotionAuthorizationStatus and if false then return not_available instead of checking the motion_permission_requested flag.

However, I'd recommend anyway that you call cordova.plugins.diagnostic.isMotionAvailable() before any other motion operations and if this returns false, then omit calls to the other operations since motion tracking is unavailable on the device.

dpa99c commented 5 years ago

The above commit should ensure that getMotionAuthorizationStatus returns not_available if activity tracking is not available on the device.

fcamblor commented 5 years ago

Yes, that's what I am (and was) doing.

But I can recall that the change you made on 5.0.1 changed the behaviour. I do think that there is some Motion permission existing on this device ... prior to 5.0.1, when I was calling requestMotionAuthorization I think it was asking for the motion permission.

I'm not 💯 about that, let me check this again with a previous version of the plugin to be sure of myself :-)

dpa99c commented 5 years ago

Looking at the iPad Mini 4 specs it does seem it has a motion coprocessor. But CMMotionActivityManager isActivityAvailable is returning false indicating that activity tracking is unavailable.

dpa99c commented 5 years ago

Interestingly, looking at the motion coprocessors, you iPad Mini 4 has the A8 whereas my iPad Air (ME913B/A) has the A7 so yours has a new coprocessor, so I wonder why it says activity tracking is unavailable since it's my understanding that it is supported on the A7 and upwards? Maybe the iOS version 10 vs 12?

fcamblor commented 5 years ago

@dpa99c Apologies, I was just checking and ... I'm testing with an iPad Mini 1 since this morning, not the iPad Mini 4 (they are very close in terms of design)

I'm going to unroll this thread and test everything again with the iPad Mini 4 this time, will keep you posted

I'm really sorry to waste your time :(

dpa99c commented 5 years ago

aha! iPad Mini 1 does not have a motion coprocessor so that explains why isMotionAvailable is false!

I'm really sorry to waste your time :(

You really haven't wasted my time as you did find an actual bug which is fixed by the commit above!

fcamblor commented 5 years ago

OK, ran the tests and it looks good with a proper iPad Mini 4 : I now have the not_determined status after the requestMotionAuthorization() call (and cannot call requestMotionAuthorization() twice, which is something expected when I have an option to skip this call by checking getMotionAuthorizationStatus() == "not_requested")

Diagnostic_plugin_ok_on_ipad_mini_4