cordova-plugin-kiosk icon indicating copy to clipboard operation
cordova-plugin-kiosk copied to clipboard

NFC reader doesn't work in Kiosk Mode after restart

Open KreoDev opened this issue 6 years ago • 14 comments

Hi, When the phone is in kiosk mode everything works perfectly up until the phone has been restarted or shut down. When the phone has been restarted nfc doesn't scan up until you exit the app and then go back into it only does everything start to work again. I'm having this issue with Android 7.0. Unfortunately all the phones I have access to have android 7.0. After doing some googling apparently Android 8.0 doesn't have the issue but unfortunately all my users are on Android 7.0.

I have created a demo ionic project that you can use to recreate the issue: https://github.com/KreoDev/Kiosk-NFC-Demo

To recreate the issue you just have to enable kiosk mode and then restart the phone and try to scan any NFC tag. Afterwards use the back button to exit the app and then go back into the app and then you will be able to start scanning NFC tags again.

KreoDev avatar Jan 23 '19 09:01 KreoDev

I can confirm that the issue actually exists on Android 8.0

Caldarelli avatar Feb 08 '19 16:02 Caldarelli

I have the same problem with Oreo. Seems like it's related to this: https://stackoverflow.com/questions/41227623/android-nfc-intent-not-working-when-app-is-started-as-launcher Any ideas?

looksystems avatar Apr 02 '19 20:04 looksystems

Also seems related to #6

looksystems avatar Apr 03 '19 07:04 looksystems

Great! Can you confirm described fix fixes it for you? btw, pull requests are welcome ;)

thaarok avatar Apr 03 '19 08:04 thaarok

Well at the time of posting, I didn't have a fix but now I do. At least for my particular situation.

In plugin.xml

   <config-file target="AndroidManifest.xml" parent="/manifest/application">
        <receiver android:name="jk.cordova.plugin.kiosk.BootCompletedReceiver" >
            <intent-filter android:priority="999">
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" /> 
            </intent-filter>
        </receiver>
    </config-file>

    <config-file target="AndroidManifest.xml" parent="/manifest">
            <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    </config-file>

    <source-file src="android/BootCompletedReceiver.java" target-dir="src/jk/cordova/plugin/kiosk" />

New file android/BootCompletedReceiver.java:

package jk.cordova.plugin.kiosk;

import jk.cordova.plugin.kiosk.KioskActivity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent;

/**

  • Used to ensure app brought front by relaunching and so receives nfc events */ public class BootCompletedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { KioskActivity.restart(context); } }

In KioskActivity.java:

public static volatile boolean restarting = false;

public static void restart(Context context) {
    restarting = true;
    System.out.println("restart app");
    String myPackage = context.getPackageName();
    Intent restartIntent = context.getPackageManager().getLaunchIntentForPackage(myPackage);
    PendingIntent intent = PendingIntent.getActivity(context, 0, restartIntent, Intent.FLAG_ACTIVITY_CLEAR_TOP);
    AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    manager.set(AlarmManager.RTC, System.currentTimeMillis() + 1, intent);
    System.exit(0);
}

In android/KioskPlugin.java:

public static final String RESTART = "restart";
public static final String IS_RESTARTING = "isRestarting";   

In android/KioskPlugin.java execute function:

        if (RESTART.equals(action)) {

            Context context = cordova.getActivity().getApplicationContext();
            KioskActivity.restart(context);

        } else if (IS_RESTARTING.equals(action)) {

            System.out.println("elapsed: " + SystemClock.elapsedRealtime());
            callbackContext.success(Boolean.toString(KioskActivity.restarting));
            return true;
            
        } 

In kiosk.js:

restart: function () {
    exec(function () {}, function (error) {
        alert("KioskPlugin.restart failed: " + error);
    }, "KioskPlugin", "restart", []);
},

isRestarting: function (callback) {
    exec(function (out) {
        callback(out == "true");
    }, function (error) {
        alert("KioskPlugin.isRestarting failed: " + error);
    }, "KioskPlugin", "isRestarting", []);
}

looksystems avatar Apr 03 '19 10:04 looksystems

can you create github pull request please?

thaarok avatar Apr 03 '19 13:04 thaarok

I'd love to but I have tight deadlines (been working 80 hour weeks for 10 weeks without a day off), so only have time to provide the "code drop" above right now. Enjoy.

looksystems avatar Apr 03 '19 13:04 looksystems

ok, thanks - will integrate soon

thaarok avatar Apr 03 '19 13:04 thaarok

Available in devel branch now - to test:

    cordova plugin add https://github.com/hkalina/cordova-plugin-kiosk.git#devel

Whoever is able to reproduce, let me know if it is working for you. Need to warn it restarts the app everytime 10 seconds after device boot up - maybe I should add some switch to turn it on/off yet. BTW, this plugin had originally startup screen from similar reasons (failing to load the app correctly when starting at system boot up) - maybe it would be more elegant way to resolve this...

thaarok avatar Apr 03 '19 22:04 thaarok

I'd suggest that the auto-restart be configured to "off" by default.

Most use cases don't require such behaviour. It is only used in our case to ensure the task is put into the foreground to receive NFC intent/events.

Our application provides its own splash screen - which deliberately waits long enough before starting the main application. We require an "auto restart" so that the user doesn't need to think about whether to relaunch themselves.

By exposing the "restart" method in js, it also allows the app to be manually restarted (rather than exit to another launcher), which is also a useful tool.

PS. timing re. restart is controlled by intent priority in plugin.xml - lower priority means longer time before notification broadcast to our app - as I understand it, the range is between -999 and +999. I chose the highest priority because that made most sense in our use case.

It could be that you choose to decouple the catching of this event and the relaunch by adding a callback handler to the boot handler. That way, app can decide what it wants to do on boot vs relaunch.

looksystems avatar Apr 04 '19 07:04 looksystems

I noticed that if you whitelist "com.android.nfc" in the SetLockTaskPackages it works.

sukanzubair avatar Aug 06 '20 16:08 sukanzubair

I noticed that if you whitelist "com.android.nfc" in the SetLockTaskPackages it works.

@sukanzubair

Sorry to be dumb, but do you have any sample code? This would be really helpful, thank you.

looksystems avatar Aug 10 '20 14:08 looksystems

Hi, So i am actually developing my app using xamarin android but I assuming that the code should be similar

I noticed that when i started my app in TaskLockMode and tried to scan an NFC tag i would receive the following message in the log

08-06 23:39:32.593 922 3408 I ActivityManager: START u0 {flg=0x10008000 cmp=com.android.nfc/.NfcRootActivity (has extras)} from uid 1027 08-06 23:39:32.601 922 3408 E ActivityManager: Attempted Lock Task Mode violation mStartActivity=ActivityRecord{9062ce6 u0 com.android.nfc/.NfcRootActivity t29}

Based on this error in log I decided to android com.android.nfc to the list of allowed applicatiosn in lock mode as follows.

var dpm = (DevicePolicyManager)MainActivity.GetSystemService(Context.DevicePolicyService); if (dpm.IsDeviceOwnerApp(MainActivity.PackageName)) { dpm.SetLockTaskPackages(GetComponentName(), new[] { MainActivity.PackageName, "com.android.nfc" }) }

This is in c# however you can have a look at the android documentation and implement the same in cordova https://developer.android.com/reference/android/app/admin/DevicePolicyManager

Hope this helps.

sukanzubair avatar Aug 10 '20 16:08 sukanzubair

I was facing a similar problem reading NFC tags with lock task mode activated on Android 10 and what actually worked for me was the second workaround on Daniel Bardyn answer

manoellribeiro avatar Jun 13 '23 17:06 manoellribeiro