/* * 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.content.Intent; 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.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 NFCSync extends Activity implements CreateNdefMessageCallback, OnNdefPushCompleteCallback { NfcAdapter mNfcAdapter; TextView mInfoText; private static final int MESSAGE_SENT = 0x1; private static final int SYNC_SUCCESSFUL = 0x2; private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_SENT: mInfoText.setText("Synchronization data sent, wait for data."); Log.i("NFC", "Message sent!"); break; case SYNC_SUCCESSFUL: mInfoText.setText("Synchronization successfull!"); Log.i("NFC", "Message sent!"); 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 synchronize."); // 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(); Log.i("NFC", "Creating Message"); 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(); // Check to see that the Activity started due to an Android Beam if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { processIntent(getIntent()); } } /** * 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]; // record 0 contains the MIME type, record 1 is the AAR, if present Object netData; Object deviceData; Object syncData; Log.i("NFC", "Getting Message!"); try { HostageDBOpenHelper dbh = new HostageDBOpenHelper(this); netData = deserialize(msg.getRecords()[0].getPayload()); deviceData = deserialize(msg.getRecords()[1].getPayload()); syncData = deserialize(msg.getRecords()[2].getPayload()); ArrayList remoteNetworkInformation = (ArrayList) netData; HashMap devices_remote = (HashMap) deviceData; HashMap devices_local = dbh.getSyncDevices(); ArrayList syncInfo = (ArrayList) syncData; 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(SYNC_SUCCESSFUL).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(); } }