1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.nfc.ndefpush; 18 19 import com.android.internal.nfc.LlcpException; 20 import com.android.internal.nfc.LlcpSocket; 21 import com.android.nfc.NfcService; 22 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.nfc.NdefMessage; 28 import android.nfc.NfcAdapter; 29 import android.os.AsyncTask; 30 import android.util.Log; 31 32 import java.io.IOException; 33 import java.util.Arrays; 34 35 /** 36 * Simple client to push the local NDEF message to a server on the remote side of an 37 * LLCP connection. The message is set via {@link NfcAdapter#setLocalNdefMessage}. 38 */ 39 public class NdefPushClient extends BroadcastReceiver { 40 private static final String TAG = "NdefPushClient"; 41 private static final int MIU = 128; 42 private static final boolean DBG = true; 43 44 /** Locked on MyTagClient.class */ 45 NdefMessage mForegroundMsg; 46 NdefPushClient(Context context)47 public NdefPushClient(Context context) { 48 context.registerReceiver(this, new IntentFilter(NfcAdapter.ACTION_LLCP_LINK_STATE_CHANGED)); 49 } 50 setForegroundMessage(NdefMessage msg)51 public boolean setForegroundMessage(NdefMessage msg) { 52 synchronized (this) { 53 boolean set = mForegroundMsg != null; 54 mForegroundMsg = msg; 55 return set; 56 } 57 } 58 getForegroundMessage()59 public NdefMessage getForegroundMessage() { 60 synchronized (this) { 61 return mForegroundMsg; 62 } 63 } 64 65 @Override onReceive(Context context, Intent intent)66 public void onReceive(Context context, Intent intent) { 67 int linkState = intent.getIntExtra(NfcAdapter.EXTRA_LLCP_LINK_STATE_CHANGED, 68 NfcAdapter.LLCP_LINK_STATE_DEACTIVATED); 69 if (linkState != NfcAdapter.LLCP_LINK_STATE_ACTIVATED) { 70 // The link was torn down, ignore 71 return; 72 } 73 74 if (DBG) Log.d(TAG, "LLCP connection up and running"); 75 76 NdefMessage foregroundMsg; 77 synchronized (this) { 78 foregroundMsg = mForegroundMsg; 79 } 80 81 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(context); 82 NdefMessage myTag = adapter.getLocalNdefMessage(); 83 84 if (foregroundMsg != null && myTag != null) { 85 if (DBG) Log.d(TAG, "sending foreground and my tag"); 86 new SendAsync().execute(foregroundMsg, myTag); 87 } else if (myTag != null) { 88 if (DBG) Log.d(TAG, "sending my tag"); 89 new SendAsync().execute(myTag); 90 } else if (foregroundMsg != null) { 91 if (DBG) Log.d(TAG, "sending foreground"); 92 new SendAsync().execute(foregroundMsg); 93 } else { 94 if (DBG) Log.d(TAG, "no tags set, bailing"); 95 return; 96 } 97 } 98 99 final class SendAsync extends AsyncTask<NdefMessage, Void, Void> { 100 @Override doInBackground(NdefMessage... msgs)101 public Void doInBackground(NdefMessage... msgs) { 102 NfcService service = NfcService.getInstance(); 103 104 // We only handle a single immediate action for now 105 NdefPushProtocol msg = new NdefPushProtocol(msgs[0], NdefPushProtocol.ACTION_IMMEDIATE); 106 byte[] buffer = msg.toByteArray(); 107 int offset = 0; 108 int remoteMiu; 109 LlcpSocket sock = null; 110 try { 111 if (DBG) Log.d(TAG, "about to create socket"); 112 // Connect to the my tag server on the remote side 113 sock = service.createLlcpSocket(0, MIU, 1, 1024); 114 if (DBG) Log.d(TAG, "about to connect to service " + NdefPushServer.SERVICE_NAME); 115 sock.connect(NdefPushServer.SERVICE_NAME); 116 117 remoteMiu = sock.getRemoteSocketMiu(); 118 if (DBG) Log.d(TAG, "about to send a " + buffer.length + " byte message"); 119 while (offset < buffer.length) { 120 int length = Math.min(buffer.length - offset, remoteMiu); 121 byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length); 122 if (DBG) Log.d(TAG, "about to send a " + length + " byte packet"); 123 sock.send(tmpBuffer); 124 offset += length; 125 } 126 } catch (IOException e) { 127 Log.e(TAG, "couldn't send tag"); 128 if (DBG) Log.d(TAG, "exception:", e); 129 } catch (LlcpException e) { 130 // Most likely the other side doesn't support the my tag protocol 131 Log.e(TAG, "couldn't send tag"); 132 if (DBG) Log.d(TAG, "exception:", e); 133 } finally { 134 if (sock != null) { 135 try { 136 if (DBG) Log.d(TAG, "about to close"); 137 sock.close(); 138 } catch (IOException e) { 139 // Ignore 140 } 141 } 142 } 143 return null; 144 } 145 } 146 } 147