<commit_before>package ch.uzh.csg.nfclib;

import java.util.ArrayList;

import android.app.Activity;
import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
import android.util.Log;
import ch.uzh.csg.nfclib.messages.NfcMessage;
import ch.uzh.csg.nfclib.util.Constants;
import ch.uzh.csg.nfclib.util.NfcMessageReassembler;
import ch.uzh.csg.nfclib.util.NfcMessageSplitter;

//TODO: javadoc
public class CustomHostApduService extends HostApduService {
	
	public static final String TAG = "CustomHostApduService";
	
	/*
	 * NXP chip supports max 255 bytes (10 bytes is header of nfc protocol)
	 */
	protected static final int MAX_WRITE_LENGTH = 245;
	
	private static Activity hostActivity;
	private static NfcEventHandler eventHandler;
	private static IMessageHandler messageHandler;
	
	private static NfcMessageSplitter messageSplitter;
	private static NfcMessageReassembler messageReassembler;
	
	private static ArrayList<NfcMessage> fragments;
	private static int index = 0;
	
	public static void init(Activity activity, NfcEventHandler eventHandler, IMessageHandler messageHandler) {
		hostActivity = activity;
		CustomHostApduService.eventHandler = eventHandler;
		CustomHostApduService.messageHandler = messageHandler;
		messageSplitter = new NfcMessageSplitter(MAX_WRITE_LENGTH);
		messageReassembler = new NfcMessageReassembler();
	}
	
	/*
	 * The empty constructor is needed by android to instantiate the service.
	 * That is the reason why most fields are static.
	 */
	public CustomHostApduService() {
		if (hostActivity == null) {
			Log.d(TAG, "activity has not been set yet or user is not in the given activity");
		}
	}

	@Override
	public byte[] processCommandApdu(byte[] bytes, Bundle extras) {
		if (hostActivity == null) {
			Log.e(TAG, "The user is not in the correct activity but tries to establish a NFC connection.");
			//TODO: add sequence number?
			return new NfcMessage(NfcMessage.ERROR, (byte) (0x00), null).getData();
		}
		
		if (selectAidApdu(bytes)) {
			Log.d(TAG, "AID selected");
			//TODO: decide based on time if to resume or restart!
			eventHandler.handleMessage(NfcEvent.NFC_INITIALIZED, null);
			return new NfcMessage(NfcMessage.AID_SELECTED, (byte) 0x01, new byte[]{NfcMessage.START_PROTOCOL}).getData();
		}
		
		return getResponse(bytes).getData();
	}
	
	private boolean selectAidApdu(byte[] bytes) {
		return bytes.length >= 2 && bytes[0] == Constants.CLA_INS_P1_P2[0] && bytes[1] == Constants.CLA_INS_P1_P2[1];
	}

	private NfcMessage getResponse(byte[] bytes) {
		if (bytes == null || bytes.length < NfcMessage.HEADER_LENGTH) {
			Log.e(TAG, "error occured when receiving message");
			eventHandler.handleMessage(NfcEvent.NFC_COMMUNICATION_ERROR, null);
			return new NfcMessage(NfcMessage.ERROR, (byte) 0x00, null);
		}
		
		NfcMessage incoming = new NfcMessage(bytes);
		Log.d(TAG, "received msg: "+incoming);
		
		byte status = (byte) (incoming.getStatus());
		
		switch (status) {
		case NfcMessage.HAS_MORE_FRAGMENTS:
			Log.d(TAG, "has more fragments");
			messageReassembler.handleReassembly(incoming);
			return new NfcMessage(NfcMessage.GET_NEXT_FRAGMENT, (byte) 0x00, null);
		case NfcMessage.DEFAULT:
			Log.d(TAG, "handle default");
			messageReassembler.handleReassembly(incoming);<commit_msg>Catched source for NPE.<commit_after>package ch.uzh.csg.nfclib;

import java.util.ArrayList;

import android.app.Activity;
import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
import android.util.Log;
import ch.uzh.csg.nfclib.messages.NfcMessage;
import ch.uzh.csg.nfclib.util.Constants;
import ch.uzh.csg.nfclib.util.NfcMessageReassembler;
import ch.uzh.csg.nfclib.util.NfcMessageSplitter;

//TODO: javadoc
public class CustomHostApduService extends HostApduService {
	
	public static final String TAG = "CustomHostApduService";
	
	/*
	 * NXP chip supports max 255 bytes (10 bytes is header of nfc protocol)
	 */
	protected static final int MAX_WRITE_LENGTH = 245;
	
	private static Activity hostActivity;
	private static NfcEventHandler eventHandler;
	private static IMessageHandler messageHandler;
	
	private static NfcMessageSplitter messageSplitter;
	private static NfcMessageReassembler messageReassembler;
	
	private static ArrayList<NfcMessage> fragments;
	private static int index = 0;
	
	public static void init(Activity activity, NfcEventHandler eventHandler, IMessageHandler messageHandler) {
		hostActivity = activity;
		CustomHostApduService.eventHandler = eventHandler;
		CustomHostApduService.messageHandler = messageHandler;
		messageSplitter = new NfcMessageSplitter(MAX_WRITE_LENGTH);
		messageReassembler = new NfcMessageReassembler();
	}
	
	/*
	 * The empty constructor is needed by android to instantiate the service.
	 * That is the reason why most fields are static.
	 */
	public CustomHostApduService() {
		if (hostActivity == null) {
			Log.d(TAG, "activity has not been set yet or user is not in the given activity");
		}
	}

	@Override
	public byte[] processCommandApdu(byte[] bytes, Bundle extras) {
		if (hostActivity == null) {
			Log.e(TAG, "The user is not in the correct activity but tries to establish a NFC connection.");
			//TODO: add sequence number?
			return new NfcMessage(NfcMessage.ERROR, (byte) (0x00), null).getData();
		}
		
		if (selectAidApdu(bytes)) {
			Log.d(TAG, "AID selected");
			//TODO: decide based on time if to resume or restart!
			eventHandler.handleMessage(NfcEvent.NFC_INITIALIZED, null);
			return new NfcMessage(NfcMessage.AID_SELECTED, (byte) 0x01, new byte[]{NfcMessage.START_PROTOCOL}).getData();
		}
		
		return getResponse(bytes).getData();
	}
	
	private boolean selectAidApdu(byte[] bytes) {
		if (bytes == null || bytes.length < 2)
			return false;
		else
			return bytes[0] == Constants.CLA_INS_P1_P2[0] && bytes[1] == Constants.CLA_INS_P1_P2[1];
	}

	private NfcMessage getResponse(byte[] bytes) {
		if (bytes == null || bytes.length < NfcMessage.HEADER_LENGTH) {
			Log.e(TAG, "error occured when receiving message");
			eventHandler.handleMessage(NfcEvent.NFC_COMMUNICATION_ERROR, null);
			return new NfcMessage(NfcMessage.ERROR, (byte) 0x00, null);
		}
		
		NfcMessage incoming = new NfcMessage(bytes);
		Log.d(TAG, "received msg: "+incoming);
		
		byte status = (byte) (incoming.getStatus());
		
		switch (status) {
		case NfcMessage.HAS_MORE_FRAGMENTS:
			Log.d(TAG, "has more fragments");
			messageReassembler.handleReassembly(incoming);
			return new NfcMessage(NfcMessage.GET_NEXT_FRAGMENT, (byte) 0x00, null);
		case NfcMessage.DEFAULT:
			Log.d(TAG, "handle default");
			messageReassembler.handleReassembly(incoming);
{'fraction_non_alphanumeric': 0.10104529616724739, 'fraction_numerical': 0.00908953188910771, 'mean_word_length': 4.884135472370766, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5045585', 'n_tokens_mistral': 2315, 'n_tokens_neox': 2095, 'n_words': 550}