javaandroidnfcsecure-elementopen-mobile-api

How to use Executor in SEservice (Open Mobile API for Android 9.0)


I'm working on NFC and currently try to write code for the Open Mobile API built into Android 9.0, but don't understand the way to pass the Executor parameter in SEService.

public class MainActivity extends Activity implements SEService.OnConnectedListener {

    final String LOG_TAG = "NfcTest";

    private SEService seService;

    private Button button;


    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        LinearLayout layout = new LinearLayout(this);
        layout.setLayoutParams(new LayoutParams(
                LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));

        button = new Button(this);
        button.setLayoutParams(new LayoutParams(
                LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));

        button.setText("Click Me");
        button.setEnabled(false);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                try {

                    Reader[] readers = seService.getReaders();
                    if (readers.length < 1)
                        return;


                    Session session = readers[0].openSession();



                    Channel channel = session.openLogicalChannel(new byte[]{
                            (byte) 0xF0, 0x51, (byte) 0xBC, 0x53, 0x54, 0x69, 0x64,
                            (byte) 0x4D, 0x6F, 0x62, 0x69, (byte) 0x6C,
                            (byte) 0x65, 0x2D, (byte) 0x49, 0x44});


                    byte[] respApdu = channel.transmit(new byte[]{
                            (byte) 0x90, 0x10, 0x00, 0x00, 0x00});

                    channel.close();

                    // Parse response APDU and show text but remove SW1 SW2 first
                    byte[] helloStr = new byte[respApdu.length - 2];
                    System.arraycopy(respApdu, 0, helloStr, 0, respApdu.length - 2);
                    Toast.makeText(MainActivity.this, new String(helloStr), Toast.LENGTH_LONG).show();
                } catch (Exception e) {
                    Log.i(LOG_TAG, "Message: " + e.getClass().getCanonicalName());
                    if(e.getClass().isInstance(new NoSuchElementException()))
                        Toast.makeText(MainActivity.this, "NFC sim", Toast.LENGTH_LONG).show();
                    else if (e.getClass().isInstance(new IOException())){
                        Toast.makeText(MainActivity.this, "No sim found", Toast.LENGTH_LONG).show();
                    }
                    else{
                        Toast.makeText(MainActivity.this, "Normal sim", Toast.LENGTH_LONG).show();
                    }
                }
            }
        });

        layout.addView(button);
        setContentView(layout);


        try {

            seService = new SEService(this, this,this);
        } catch (SecurityException e) {
            Log.e(LOG_TAG, "Binding not allowed, uses-permission org.simalliance.openmobileapi.SMARTCARD?");
        } catch (Exception e) {
            Log.e(LOG_TAG, "Exception: " + e.getMessage());
        }
    }

    @Override
    protected void onDestroy() {
        if (seService != null && seService.isConnected()) {
            seService.shutdown();
        }
        super.onDestroy();
    }

    public void serviceConnected(SEService service) {
        Log.i(LOG_TAG, "seviceConnected()");
        button.setEnabled(true);
    }

    @Override
    public void onConnected() {

    }
}

Problem occurs on:

seService = new SEService(this, this,this);

First and last parameter accepted the middle one executer appears error!

java.util.concurrent.Executor this

How to pass this?


Solution

  • You get this error because the second aregument of the constructor SEService must be a java.util.concurrent.Executor. You MainActivity (this object) does not implement an executor.

    THis executor is used by the SEService to invoke callback methods. So you have to create such an executor yourself in order to pass it to SEService. YOu could, for instance, simply create an ExecutorService with a single worker thread to handle the callbacks:

    ExecutorService pool = Executors.newSingleThreadExecutor();
    seService = new SEService(this, pool, this);
    

    Be aware though, that these callbacks are then executed on a worker thread (not the main thread of your app). Consequently, if you want to perform any UI operations from within the callbacks, you will need to explicitly run them on the UI thread, e.g.

    runOnUiThread(new Runnable() {
        void run() {
            button.setEnabled(true); // ... or some other UI modifications
        }
    });