1f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen/* 2f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * Copyright (C) 2012 The Android Open Source Project 3f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * 4f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * Licensed under the Apache License, Version 2.0 (the "License"); 5f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * you may not use this file except in compliance with the License. 6f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * You may obtain a copy of the License at 7f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * 8f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * http://www.apache.org/licenses/LICENSE-2.0 9f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * 10f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * Unless required by applicable law or agreed to in writing, software 11f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * distributed under the License is distributed on an "AS IS" BASIS, 12f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * See the License for the specific language governing permissions and 14f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * limitations under the License. 15f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen */ 16f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenpackage com.android.nfc.handover; 17f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 18b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.DeviceHost.LlcpServerSocket; 19b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.DeviceHost.LlcpSocket; 20b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.LlcpException; 21b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.NfcService; 22b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.beam.BeamManager; 23b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.beam.BeamReceiveService; 24b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.beam.BeamTransferRecord; 25b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 26b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.bluetooth.BluetoothDevice; 27b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.content.Context; 28b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.content.Intent; 29f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport android.nfc.FormatException; 30f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport android.nfc.NdefMessage; 31b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.os.UserHandle; 32f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport android.util.Log; 33f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 34f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport java.io.ByteArrayOutputStream; 35f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport java.io.IOException; 36f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport java.util.Arrays; 37f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 38f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenpublic final class HandoverServer { 39b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static final String HANDOVER_SERVICE_NAME = "urn:nfc:sn:handover"; 40b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static final String TAG = "HandoverServer"; 41b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static final Boolean DBG = false; 42f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 43b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales static final int MIU = 128; 44f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 45b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales final HandoverDataParser mHandoverDataParser; 46f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen final int mSap; 47f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen final Callback mCallback; 48b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales private final Context mContext; 49f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 50f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen ServerThread mServerThread = null; 51f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen boolean mServerRunning = false; 52f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 53f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen public interface Callback { 54f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen void onHandoverRequestReceived(); 55aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales void onHandoverBusy(); 56f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 57f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 58b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales public HandoverServer(Context context, int sap, HandoverDataParser manager, Callback callback) { 59b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mContext = context; 60f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mSap = sap; 61b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mHandoverDataParser = manager; 62f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mCallback = callback; 63f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 64f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 65f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen public synchronized void start() { 66f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (mServerThread == null) { 67f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerThread = new ServerThread(); 68f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerThread.start(); 69f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerRunning = true; 70f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 71f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 72f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 73f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen public synchronized void stop() { 74f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (mServerThread != null) { 75f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerThread.shutdown(); 76f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerThread = null; 77f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerRunning = false; 78f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 79f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 80f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 81f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen private class ServerThread extends Thread { 82f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen private boolean mThreadRunning = true; 83f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen LlcpServerSocket mServerSocket; 84f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 85f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen @Override 86f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen public void run() { 87f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen boolean threadRunning; 88f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 89f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen threadRunning = mThreadRunning; 90f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 91f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 92f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen while (threadRunning) { 93f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen try { 94f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 95f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerSocket = NfcService.getInstance().createLlcpServerSocket(mSap, 96f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen HANDOVER_SERVICE_NAME, MIU, 1, 1024); 97f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 98f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (mServerSocket == null) { 99f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "failed to create LLCP service socket"); 100f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen return; 101f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 102f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "created LLCP service socket"); 103f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 104f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen threadRunning = mThreadRunning; 105f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 106f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 107f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen while (threadRunning) { 108f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen LlcpServerSocket serverSocket; 109f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 110f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen serverSocket = mServerSocket; 111f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 112f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 113f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (serverSocket == null) { 114f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "Server socket shut down."); 115f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen return; 116f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 117f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "about to accept"); 118f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen LlcpSocket communicationSocket = serverSocket.accept(); 119f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "accept returned " + communicationSocket); 120f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (communicationSocket != null) { 121f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen new ConnectionThread(communicationSocket).start(); 122f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 123f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 124f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 125f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen threadRunning = mThreadRunning; 126f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 127f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 128f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "stop running"); 129f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } catch (LlcpException e) { 130f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen Log.e(TAG, "llcp error", e); 131f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } catch (IOException e) { 132f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen Log.e(TAG, "IO error", e); 133f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } finally { 134f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 135f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (mServerSocket != null) { 136f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "about to close"); 137f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen try { 138f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerSocket.close(); 139f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } catch (IOException e) { 140f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen // ignore 141f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 142f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerSocket = null; 143f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 144f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 145f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 146f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 147f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 148f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen threadRunning = mThreadRunning; 149f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 150f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 151f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 152f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 153f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen public void shutdown() { 154f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 155f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mThreadRunning = false; 156f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (mServerSocket != null) { 157f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen try { 158f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerSocket.close(); 159f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } catch (IOException e) { 160f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen // ignore 161f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 162f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mServerSocket = null; 163f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 164f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 165f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 166f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 167f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 168f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen private class ConnectionThread extends Thread { 169f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen private final LlcpSocket mSock; 170f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 171f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen ConnectionThread(LlcpSocket socket) { 172f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen super(TAG); 173f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mSock = socket; 174f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 175f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 176f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen @Override 177f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen public void run() { 178f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "starting connection thread"); 179f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 180f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 181f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen try { 182f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen boolean running; 183f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 184f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen running = mServerRunning; 185f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 186f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 187f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen byte[] partial = new byte[mSock.getLocalMiu()]; 188f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 189f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen NdefMessage handoverRequestMsg = null; 190f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen while (running) { 191f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen int size = mSock.receive(partial); 192f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (size < 0) { 193f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen break; 194f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 195f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen byteStream.write(partial, 0, size); 196f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen // 1) Try to parse a handover request message from bytes received so far 197f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen try { 198f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen handoverRequestMsg = new NdefMessage(byteStream.toByteArray()); 199f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } catch (FormatException e) { 200f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen // Ignore, and try to fetch more bytes 201f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 202f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 203f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (handoverRequestMsg != null) { 204b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales BeamManager beamManager = BeamManager.getInstance(); 205b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 206b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (beamManager.isBeamInProgress()) { 207aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales mCallback.onHandoverBusy(); 208b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales break; 209b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 210b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 211f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen // 2) convert to handover response 212b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales HandoverDataParser.IncomingHandoverData handoverData 213b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales = mHandoverDataParser.getIncomingHandoverData(handoverRequestMsg); 214b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (handoverData == null) { 215f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen Log.e(TAG, "Failed to create handover response"); 216f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen break; 217f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 218f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 219f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen // 3) send handover response 220f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen int offset = 0; 221b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales byte[] buffer = handoverData.handoverSelect.toByteArray(); 222f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen int remoteMiu = mSock.getRemoteMiu(); 223f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen while (offset < buffer.length) { 224f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen int length = Math.min(buffer.length - offset, remoteMiu); 225f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length); 226f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mSock.send(tmpBuffer); 227f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen offset += length; 228f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 229f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen // We're done 230f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mCallback.onHandoverRequestReceived(); 231b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (!beamManager.startBeamReceive(mContext, handoverData.handoverData)) { 232aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales mCallback.onHandoverBusy(); 233aaca83594d177442e993a8ba68349a5f7cb31200Andres Morales break; 234b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 235be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project // We can process another handover transfer 236be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project byteStream = new ByteArrayOutputStream(); 237f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 238f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 239f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen synchronized (HandoverServer.this) { 240f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen running = mServerRunning; 241f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 242f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 243f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen 244f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } catch (IOException e) { 245f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "IOException"); 246f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } finally { 247f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen try { 248f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "about to close"); 249f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen mSock.close(); 250f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } catch (IOException e) { 251f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen // ignore 252f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 253f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen try { 254f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen byteStream.close(); 255f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } catch (IOException e) { 256f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen // ignore 257f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 258f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 259f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen if (DBG) Log.d(TAG, "finished connection thread"); 260f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 261f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen } 262f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen} 263b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 264