/* * Copyright (C) 2011 The Android Open Source Project * * 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 de.tudarmstadt.informatik.hostage.sync.nfc; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import android.annotation.TargetApi; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.NfcAdapter.CreateNdefMessageCallback; import android.nfc.NfcAdapter.OnNdefPushCompleteCallback; import android.nfc.NfcEvent; import android.nfc.tech.NfcF; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Parcelable; import android.util.Log; import android.widget.TextView; import android.widget.Toast; import de.tudarmstadt.informatik.hostage.R; import de.tudarmstadt.informatik.hostage.logging.NetworkRecord; import de.tudarmstadt.informatik.hostage.logging.SyncInfoRecord; import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper; import de.tudarmstadt.informatik.hostage.sync.tracing.TracingSyncService; @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public class NFCSyncActivity extends Activity implements CreateNdefMessageCallback, OnNdefPushCompleteCallback { NfcAdapter mNfcAdapter; TextView mInfoText; private static final int MESSAGE_SENT = 0x1; private static final int MESSAGE_RECEIVED = 0x3; private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_SENT: runOnUiThread(new Runnable() { public void run() { Toast.makeText(NFCSyncActivity.this, "Data sent!", Toast.LENGTH_LONG).show(); } }); break; case MESSAGE_RECEIVED: runOnUiThread(new Runnable() { public void run() { Toast.makeText(NFCSyncActivity.this, "Data recieved!", Toast.LENGTH_LONG).show(); } }); break; } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_nfc); mInfoText = (TextView) findViewById(R.id.nfc_text_view); // Check for available NFC Adapter mNfcAdapter = NfcAdapter.getDefaultAdapter(this); if (mNfcAdapter == null) { mInfoText.setText("NFC is not available on this device."); } else if(!mNfcAdapter.isEnabled()){ mInfoText.setText("Enable Android Beam before synchronizing."); } else { mInfoText.setText("Hold phones together to send or recieve data."); // Register callback to set NDEF message mNfcAdapter.setNdefPushMessageCallback(this, this); // Register callback to listen for message-sent success mNfcAdapter.setOnNdefPushCompleteCallback(this, this); } } /** * Implementation for the CreateNdefMessageCallback interface */ @Override public NdefMessage createNdefMessage(NfcEvent event) { // Get Networkdata HostageDBOpenHelper dbh = new HostageDBOpenHelper(this); ArrayList localNetworkInformation = dbh.getNetworkInformation(); HashMap devices_local = dbh.getSyncDevices(); ArrayList syncInfo = dbh.getSyncInfo(); NdefMessage msg = null; try { NdefRecord netData = NdefRecord.createMime("application/de.tudarmstadt.informatik.hostage", serialize(localNetworkInformation)); NdefRecord deviceData = NdefRecord.createMime("application/de.tudarmstadt.informatik.hostage", serialize(devices_local)); NdefRecord syncData = NdefRecord.createMime("application/de.tudarmstadt.informatik.hostage", serialize(syncInfo)); msg = new NdefMessage(netData, deviceData, syncData); } catch (IOException e) { e.printStackTrace(); } return msg; } /** * Implementation for the OnNdefPushCompleteCallback interface */ @Override public void onNdefPushComplete(NfcEvent arg0) { // A handler is needed to send messages to the activity when this // callback occurs, because it happens from a binder thread mHandler.obtainMessage(MESSAGE_SENT).sendToTarget(); } @Override public void onNewIntent(Intent intent) { // onResume gets called after this to handle the intent setIntent(intent); } // HELPER @Override public void onResume() { super.onResume(); IntentFilter[] mIntentFilters = null; PendingIntent mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); // set an intent filter for all MIME data IntentFilter ndefIntent = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); try { ndefIntent.addDataType("*/*"); mIntentFilters = new IntentFilter[] { ndefIntent }; } catch (Exception e) { Log.e("TagDispatch", e.toString()); } String[][] mNFCTechLists = new String[][] { new String[] { NfcF.class.getName() } }; if (mNfcAdapter != null) mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, mIntentFilters, mNFCTechLists); // Check to see that the Activity started due to an Android Beam if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { processIntent(getIntent()); } } @Override public void onPause() { super.onPause(); if (mNfcAdapter != null) mNfcAdapter.disableForegroundDispatch(this); } /** * Parses the NDEF Message from the intent and prints to the TextView */ void processIntent(Intent intent) { Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); // only one message sent during the beam NdefMessage msg = (NdefMessage) rawMsgs[0]; try { HostageDBOpenHelper dbh = new HostageDBOpenHelper(this); ArrayList remoteNetworkInformation = (ArrayList) deserialize(msg.getRecords()[0].getPayload()); HashMap devices_remote = (HashMap) deserialize(msg.getRecords()[1].getPayload()); HashMap devices_local = dbh.getSyncDevices(); ArrayList syncInfo = (ArrayList) deserialize(msg.getRecords()[2].getPayload()); long tracing_timestamp = 0; if(devices_local.containsKey(TracingSyncService.REMOTE_DEVICE)) tracing_timestamp = devices_local.get(TracingSyncService.REMOTE_DEVICE); for(Iterator i = devices_remote.keySet().iterator(); i.hasNext(); ){ String key = i.next(); if((devices_local.containsKey(key) && devices_local.get(key) >= devices_remote.get(key)) || (tracing_timestamp > devices_remote.get(key))){ i.remove(); } } for ( Iterator i = syncInfo.iterator(); i.hasNext(); ){ SyncInfoRecord info = i.next(); if(!devices_remote.containsKey(info.getDeviceID())){ i.remove(); } } dbh.updateSyncDevices(devices_remote); dbh.updateSyncInfo(syncInfo); dbh.updateNetworkInformation(remoteNetworkInformation); mHandler.obtainMessage(MESSAGE_RECEIVED).sendToTarget(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static Object deserialize(byte[] data) throws IOException, ClassNotFoundException { ByteArrayInputStream in = new ByteArrayInputStream(data); ObjectInputStream is = new ObjectInputStream(in); return is.readObject(); } private static byte[] serialize(Object obj) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream os = new ObjectOutputStream(out); os.writeObject(obj); return out.toByteArray(); } }