/*
* Copyright (C) 2011 Stanford University MobiSocial Lab
* http://mobisocial.stanford.edu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package mobisocial.nfc;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import android.net.Uri;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.util.Log;
public class ConnectionHandoverManager implements NdefHandler, PrioritizedHandler {
public static final String USER_HANDOVER_PREFIX = "ndef://wkt:hr/";
public static final String TAG = "connectionhandover";
public static final int HANDOVER_PRIORITY = 5;
private final Set<ConnectionHandover> mmConnectionHandovers = new LinkedHashSet<ConnectionHandover>();
public ConnectionHandoverManager() {
}
public void addConnectionHandover(ConnectionHandover handover) {
mmConnectionHandovers.add(handover);
}
public void clearConnectionHandovers() {
mmConnectionHandovers.clear();
}
public boolean removeConnectionHandover(ConnectionHandover handover) {
return mmConnectionHandovers.remove(handover);
}
/**
* Returns the (mutable) set of active connection handover
* responders.
*/
public Set<ConnectionHandover> getConnectionHandoverResponders() {
return mmConnectionHandovers;
}
//@Override
public final int handleNdef(NdefMessage[] handoverRequest) {
// TODO: What does this mean?
return doHandover(handoverRequest[0]);
}
public final int doHandover(NdefMessage handoverRequest) {
int handoverRecordPos = findHandoverRequest(handoverRequest);
if (handoverRecordPos == -1) {
return NDEF_PROPAGATE;
}
if (findUserspaceHandoverRequest(handoverRequest) != -1) {
Uri uri;
try {
uri = NdefFactory.parseUri(handoverRequest.getRecords()[0]);
} catch (FormatException e) {
Log.e(TAG, "Bad handover record.", e);
return NDEF_PROPAGATE;
}
handoverRequest = NdefFactory.fromNdefUri(uri);
handoverRecordPos = 0;
}
NdefRecord[] records = handoverRequest.getRecords();
for (int i = handoverRecordPos + 2; i < records.length; i++) {
Iterator<ConnectionHandover> handovers = mmConnectionHandovers.iterator();
while (handovers.hasNext()) {
ConnectionHandover handover = handovers.next();
if (handover.supportsRequest(records[i])) {
try {
Log.d(TAG, "Attempting handover " + handover);
handover.doConnectionHandover(handoverRequest, handoverRecordPos, i);
return NDEF_CONSUME;
} catch (IOException e) {
Log.w(TAG, "Handover failed.", e);
// try the next one.
}
}
}
}
return NDEF_PROPAGATE;
}
//@Override
public int getPriority() {
return HANDOVER_PRIORITY;
}
/**
* Returns true if the given Ndef message contains a connection
* handover request.
*/
public static int findHandoverRequest(NdefMessage ndef) {
NdefRecord[] records = (ndef).getRecords();
for (int i = 0; i < records.length; i++) {
if (records[i].getTnf() == NdefRecord.TNF_WELL_KNOWN
&& Arrays.equals(records[i].getType(), NdefRecord.RTD_HANDOVER_REQUEST)) {
return i;
}
}
return findUserspaceHandoverRequest(ndef);
}
public static boolean isHandoverRequest(NdefMessage ndefMessage) {
NdefRecord ndef = ndefMessage.getRecords()[0];
return (ndef.getTnf() == NdefRecord.TNF_WELL_KNOWN
&& Arrays.equals(ndef.getType(), NdefRecord.RTD_HANDOVER_REQUEST));
}
// User-space handover:
// TODO: Support uri profile
private static int findUserspaceHandoverRequest(NdefMessage ndef) {
NdefRecord[] records = (ndef).getRecords();
for (int i = 0; i < records.length; i++) {
try {
String uriStr = NdefFactory.parseUri(records[i]).toString();
if (uriStr.startsWith(USER_HANDOVER_PREFIX)) {
return i;
}
} catch (FormatException e) { }
}
return -1;
}
}