Contact HostApduService from Activity

I asked this question here , but was marked as a duplicate - however, I did not find a useful solution mentioned in the comments. Here I ask again for details ...

I am making an example application (PoC) on HCE and using HostApduService according to the Android user guide. I created two applications
1) ReaderApp - acts as a card reader 2) HCEApp - card emulation

In HCEApp, I created a class "MyService" extending HostApduService

public class MyService extends HostApduService {

private int messageCounter;
private final String TAG = "MyService";

Intent mIntent;

@Override
public void onCreate() {
    super.onCreate();
    Log.i(TAG, "onCreate");

    mIntent = new Intent(this, MyActivity.class);
    mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(mIntent);
}

/**
 * returned bytes will be sent as response. This method runs in Main thread
 * so return ASAP.
 */

@Override
public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
    if (selectAidApdu(apdu)) {
        Log.i(TAG, "Application selected");
        return getWelcomeMessage();
    } else {
        Log.i(TAG, "Received: " + new String(apdu));
        return getNextMessage();
    }
}

private byte[] getWelcomeMessage() {
    return "Hello Desktop!".getBytes();
}

private byte[] getNextMessage() {
    return ("Message from android: " + messageCounter++).getBytes();
}

private boolean selectAidApdu(byte[] apdu) {

    if (apdu != null) {
        for (byte b : apdu) {
            System.out.printf("0x%02X", b);
        }
    }

    return apdu.length >= 2 && apdu[0] == (byte) 0
            && apdu[1] == (byte) 0xa4;
}

@Override
public void onDeactivated(int reason) {
    Log.i(TAG, "Deactivated: " + reason);
}

@Override
public boolean onUnbind(Intent intent) {
    return super.onUnbind(intent);
}

}

onCreate(), MyActivity, MyService. > .

, , " onBind()" HostApduService,

@Override
public final IBinder onBind(Intent intent) {
    return mMessenger.getBinder();
}

, , . .


iuq

+4
2

onBind , , BroadcastReceiver, . bind BroadcastReceiver , start. BroadcastReceiver - , , , , .

, , , startService (). onCreate, onCreate , .

public void sendDataToService(){
    Intent intent = new Intent(context, MyService.class);
    intent.putExtra("message", SOME_DATA);
    context.startService(intent);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    // Check if intent has extras
    if(intent.getExtras() != null){

        // Get message
        int message = intent.getExtras().getInt("message");
    }

    return START_NOT_STICKY;
}

- , "startService" , , , , , , , .

: BTW. , LocationService, .

+1

. HostApduService, Messenger, HostApduService onBind.

. ( MyActivity , MyHostApduServiceSubclass). MyActivity :

private Messenger mAPDUMessenger;
...
@Override
protected void onStart() {
    super.onStart();
    Context context = getApplicationContext();
    Intent apduIntent = new Intent(montext, ContactlessApduService.class);
    context.bindService(apduIntent, mAPDUConnection, Context.BIND_AUTO_CREATE);
}
...
private ServiceConnection mAPDUConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName className, IBinder service) {
        // The HostApduService has a final override on the onBind() service method that returns
        // an IMessageHandler interface that we can grab and use to send messages back to the
        // terminal - would be better to get a handle to the running instance of the service so
        // that we could make use of the HostApduService#sendResponseApdu public method
        mAPDUMessenger = new Messenger(service);
        registerAPDUMessengerIntentFilters();
        // ^ This method sets up my handlers for local broadcast messages my BroadcastReceiver processes.
    }
...
}
...
private void registerAPDUMessengerIntentFilters() {
    LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(MyActivity.this);

    IntentFilter intentFilter = new IntentFilter(MyHostApduServiceSubclass.ACTION_PPSE_APDU_SELECT);
    lbm.registerReceiver(apduMessageBroadcastReceiver, intentFilter);
}
...
BroadcastReceiver apduMessageBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(MyHostApduServiceSubclass.ACTION_PPSE_APDU_SELECT)) {
            sendResponseApdu(MyActivity.PPSE_APDU_SELECT_RESPONSE_BYTES);
        }
    }
};
...
public final void sendResponseApdu(byte[] responseApdu) {
    Message responseMsg = Message.obtain(null, MyHostApduServiceSubclass.MSG_RESPONSE_APDU);
    // ^ Note here that because MSG_RESPONSE_APDU is the message type
    //   defined in the abstract HostApduService class, I had to override
    //   the definition in my subclass to expose it for use from MyActivity.
    //   Same with the KEY_DATA constant value below.
    Bundle dataBundle = new Bundle();
    dataBundle.putByteArray(MyHostApduServiceSubclass.KEY_DATA, responseApdu);
    responseMsg.setData(dataBundle);
    try {
        mAPDUMessenger.send(responseMsg);
    } catch (RemoteException e) {
        // Do something with the failed message
    }
}

HostApduService , , APDU . MyHostApduServiceSubclass:

public static final String ACTION_PPSE_APDU_SELECT = "ACTION_PPSE_APDU_SELECT";

// Abstract super class constant overrides
public static final String KEY_DATA = "data";
public static final int MSG_RESPONSE_APDU = 1;

@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
    Context context = getApplicationContext();
    LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
    if (Arrays.equals(MyHostApduServiceSubclass.PPSE_APDU_SELECT_BYTES, commandApdu)) {
        lbm.sendBroadcast(new Intent(ACTION_PPSE_APDU_SELECT));
    }
    return null;
    // ^ Note the need to return null so that the other end waits for the
    //   activity to send the response via the Messenger handle
}
0

Source: https://habr.com/ru/post/1547717/


All Articles