1bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde/*
2bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* Copyright (C) 2015 Samsung System LSI
3bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* Licensed under the Apache License, Version 2.0 (the "License");
4bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* you may not use this file except in compliance with the License.
5bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* You may obtain a copy of the License at
6bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde*
7bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde*      http://www.apache.org/licenses/LICENSE-2.0
8bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde*
9bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* Unless required by applicable law or agreed to in writing, software
10bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* distributed under the License is distributed on an "AS IS" BASIS,
11bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* See the License for the specific language governing permissions and
13bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde* limitations under the License.
14bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde*/
15bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondepackage com.android.bluetooth;
16bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
17bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport java.io.IOException;
18bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport java.util.concurrent.CountDownLatch;
19bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
20bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport javax.obex.ObexSession;
21bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport javax.obex.ResponseCodes;
22bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport javax.obex.ServerSession;
23bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
24bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.bluetooth.BluetoothAdapter;
25bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.bluetooth.BluetoothDevice;
26bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.bluetooth.BluetoothServerSocket;
27bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.bluetooth.BluetoothSocket;
28bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.util.Log;
29bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
30bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde/**
31bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Wraps multiple BluetoothServerSocket objects to make it possible to accept connections on
32bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * both a RFCOMM and L2CAP channel in parallel.<br>
33bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Create an instance using {@link #create()}, which will block until the sockets have been created
34bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * and channel numbers have been assigned.<br>
35bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Use {@link #getRfcommChannel()} and {@link #getL2capPsm()} to get the channel numbers to
36bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * put into the SDP record.<br>
37bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * Call {@link #shutdown(boolean)} to terminate the accept threads created by the call to
38bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * {@link #create(IObexConnectionHandler)}.<br>
39bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * A reference to an object of this type cannot be reused, and the {@link BluetoothServerSocket}
40bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * object references passed to this object will be closed by this object, hence cannot be reused
41bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * either (This is needed, as the only way to interrupt an accept call is to close the socket...)
42bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * <br>
43bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * When a connection is accepted,
44bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * {@link IObexConnectionHandler#onConnect(BluetoothDevice, BluetoothSocket)} will be called.<br>
45bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * If the an error occur while waiting for an incoming connection
46bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * {@link IObexConnectionHandler#onConnect(BluetoothDevice, BluetoothSocket)} will be called.<br>
47bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde * In both cases the {@link ObexServerSockets} object have terminated, and a new must be created.
48bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde */
49bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondepublic class ObexServerSockets {
50bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private final String TAG;
51bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private static final String STAG = "ObexServerSockets";
52bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private static final boolean D = true; // TODO: set to false!
53bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private static final int NUMBER_OF_SOCKET_TYPES = 2; // increment if LE will be supported
54bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
55bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private final IObexConnectionHandler mConHandler;
56bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /* The wrapped sockets */
57bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private final BluetoothServerSocket mRfcommSocket;
58bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private final BluetoothServerSocket mL2capSocket;
59bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /* Handles to the accept threads. Needed for shutdown. */
60bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private SocketAcceptThread mRfcommThread = null;
61bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private SocketAcceptThread mL2capThread = null;
62bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
63bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private volatile boolean mConAccepted = false;
64bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
65bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private static volatile int sInstanceCounter = 0;
66bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
67bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private ObexServerSockets(IObexConnectionHandler conHandler,
68bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            BluetoothServerSocket rfcommSocket,
69bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            BluetoothServerSocket l2capSocket) {
70bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mConHandler = conHandler;
71bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mRfcommSocket = rfcommSocket;
72bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mL2capSocket = l2capSocket;
73bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        TAG = "ObexServerSockets" + sInstanceCounter++;
74bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
75bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
76bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
77bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Creates an RFCOMM {@link BluetoothServerSocket} and a L2CAP {@link BluetoothServerSocket}
78bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @param validator a reference to the {@link IObexConnectionHandler} object to call
79bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     *                  to validate an incoming connection.
80bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @return a reference to a {@link ObexServerSockets} object instance.
81bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @throws IOException if it occurs while creating the {@link BluetoothServerSocket}s.
82bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
83bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    public static ObexServerSockets create(IObexConnectionHandler validator) {
84bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        return create(validator, BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP,
85bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP);
86bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
87bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
88bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
89bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Creates an RFCOMM {@link BluetoothServerSocket} and a L2CAP {@link BluetoothServerSocket}
90bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * with specific l2cap and RFCOMM channel numbers. It is the responsibility of the caller to
91bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * ensure the numbers are free and can be used, e.g. by calling {@link #getL2capPsm()} and
92bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * {@link #getRfcommChannel()} in {@link ObexServerSockets}.
93bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @param validator a reference to the {@link IObexConnectionHandler} object to call
94bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     *                  to validate an incoming connection.
95bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @return a reference to a {@link ObexServerSockets} object instance.
96bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @throws IOException if it occurs while creating the {@link BluetoothServerSocket}s.
97bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     *
98bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * TODO: Make public when it becomes possible to determine that the listen-call
99bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     *       failed due to channel-in-use.
100bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
101bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private static ObexServerSockets create(IObexConnectionHandler validator,
102bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            int rfcommChannel, int l2capPsm) {
103bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(D) Log.d(STAG,"create(rfcomm = " +rfcommChannel + ", l2capPsm = " + l2capPsm +")");
104bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
105bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(bt == null) {
106bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            throw new RuntimeException("No bluetooth adapter...");
107bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
108bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        BluetoothServerSocket rfcommSocket = null;
109bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        BluetoothServerSocket l2capSocket = null;
110bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        boolean initSocketOK = false;
111bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        final int CREATE_RETRY_TIME = 10;
112bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
113bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        // It's possible that create will fail in some cases. retry for 10 times
114bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        for (int i = 0; i < CREATE_RETRY_TIME; i++) {
115bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            initSocketOK = true;
116bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            try {
117bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                if(rfcommSocket == null) {
118bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    rfcommSocket = bt.listenUsingRfcommOn(rfcommChannel);
119bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                }
120bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                if(l2capSocket == null) {
121bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    l2capSocket = bt.listenUsingL2capOn(l2capPsm);
122bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                }
123bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            } catch (IOException e) {
124bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                Log.e(STAG, "Error create ServerSockets ",e);
125bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                initSocketOK = false;
126bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            }
127bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            if (!initSocketOK) {
128bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                // Need to break out of this loop if BT is being turned off.
129bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                int state = bt.getState();
130bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                if ((state != BluetoothAdapter.STATE_TURNING_ON) &&
131bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    (state != BluetoothAdapter.STATE_ON)) {
132bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    Log.w(STAG, "initServerSockets failed as BT is (being) turned off");
133bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    break;
134bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                }
135bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                try {
136bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    if (D) Log.v(STAG, "waiting 300 ms...");
137bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    Thread.sleep(300);
138bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                } catch (InterruptedException e) {
139bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    Log.e(STAG, "create() was interrupted");
140bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                }
141bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            } else {
142bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                break;
143bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            }
144bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
145bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
146bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if (initSocketOK) {
147bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            if (D) Log.d(STAG, "Succeed to create listening sockets ");
148bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            ObexServerSockets sockets = new ObexServerSockets(validator, rfcommSocket, l2capSocket);
149bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            sockets.startAccept();
150bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            return sockets;
151bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        } else {
152bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            Log.e(STAG, "Error to create listening socket after " + CREATE_RETRY_TIME + " try");
153bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            return null;
154bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
155bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
156bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
157bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
158bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Returns the channel number assigned to the RFCOMM socket. This will be a static value, that
159bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * should be reused for multiple connections.
160bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @return the RFCOMM channel number
161bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
162bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    public int getRfcommChannel() {
163bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        return mRfcommSocket.getChannel();
164bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
165bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
166bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
167bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Returns the channel number assigned to the L2CAP socket. This will be a static value, that
168bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * should be reused for multiple connections.
169bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @return the L2CAP channel number
170bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
171bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    public int getL2capPsm() {
172bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        return mL2capSocket.getChannel();
173bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
174bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
175bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
176bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Initiate the accept threads.
177bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Will create a thread for each socket type. an incoming connection will be signaled to
178bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * the {@link IObexConnectionValidator#onConnect()}, at which point both threads will exit.
179bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
180bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private void startAccept() {
181bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(D) Log.d(TAG,"startAccept()");
182bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        prepareForNewConnect();
183bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
184bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mRfcommThread = new SocketAcceptThread(mRfcommSocket);
185bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mRfcommThread.start();
186bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
187bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mL2capThread = new SocketAcceptThread(mL2capSocket);
188bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mL2capThread.start();
189bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
190bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
191bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
192bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Set state to accept new incoming connection. Will cause the next incoming connection to be
193bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Signaled through {@link IObexConnectionValidator#onConnect()};
194bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
195bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    public void prepareForNewConnect() {
196bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(D) Log.d(TAG, "prepareForNewConnect()");
197bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mConAccepted = false;
198bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
199bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
200bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
201bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Called from the AcceptThreads to signal an incoming connection.
202bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * This is the entry point that needs to synchronize between the accept
203bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * threads, and ensure only a single connection is accepted.
204bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * {@link mAcceptedSocket} is used a state variable.
205bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @param device the connecting device.
206bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @param conSocket the socket associated with the connection.
207bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @return true if the connection is accepted, false otherwise.
208bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
209bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    synchronized private boolean onConnect(BluetoothDevice device, BluetoothSocket conSocket) {
210bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(D) Log.d(TAG, "onConnect() socket: " + conSocket + " mConAccepted = " + mConAccepted);
211bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(mConAccepted  == false && mConHandler.onConnect(device, conSocket) == true) {
212bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            mConAccepted = true; // TODO: Reset this when ready to accept new connection
213bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            /* Signal the remaining threads to stop.
214bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            shutdown(false); */ // UPDATE: TODO: remove - redesigned to keep running...
215bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            return true;
216bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
217bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        return false;
218bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
219bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
220bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
221bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Signal to the {@link IObexConnectionHandler} that an error have occurred.
222bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
223bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    synchronized private void onAcceptFailed() {
224bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        Log.w(TAG,"onAcceptFailed() calling shutdown...");
225bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mConHandler.onAcceptFailed();
226bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        shutdown(false);
227bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
228bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
229bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
230bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * Terminate any running accept threads
231bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * @param block Set true to block the calling thread until the AcceptThreads
232bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * has ended execution
233bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
234bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    synchronized public void shutdown(boolean block) {
235bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(D) Log.d(TAG, "shutdown(block = " + block + ")");
236bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(mRfcommThread != null) {
237bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            mRfcommThread.shutdown();
238bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
239bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(mL2capThread != null){
240bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            mL2capThread.shutdown();
241bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
242bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if(block == true) {
243bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            while(mRfcommThread != null || mL2capThread != null) {
244bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                try {
245bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    if(mRfcommThread != null) {
246bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        mRfcommThread.join();
247bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        mRfcommThread = null;
248bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    }
249bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    if(mL2capThread != null) {
250bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        mL2capThread.join();
251bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        mL2capThread = null;
252bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    }
253bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                } catch (InterruptedException e) {
254bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    Log.i(TAG, "shutdown() interrupted, continue waiting...", e);
255bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                }
256bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            }
257bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        } else {
258bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            mRfcommThread = null;
259bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            mL2capThread = null;
260bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
261bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
262bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
263bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    /**
264bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * A thread that runs in the background waiting for remote an incoming
265bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * connect. Once a remote socket connects, this thread will be
266bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * shutdown. When the remote disconnect, this thread shall be restarted to
267bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     * accept a new connection.
268bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde     */
269bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    private class SocketAcceptThread extends Thread {
270bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
271bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        private boolean mStopped = false;
272bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        private final BluetoothServerSocket mServerSocket;
273bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
274bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        /**
275bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         * Create a SocketAcceptThread
276bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         * @param serverSocket shall never be null.
277bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         * @param latch shall never be null.
278bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         * @throws IllegalArgumentException
279bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         */
280bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        public SocketAcceptThread(BluetoothServerSocket serverSocket) {
281bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            if(serverSocket == null) {
282bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                throw new IllegalArgumentException("serverSocket cannot be null");
283bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            }
284bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            mServerSocket = serverSocket;
285bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
286bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
287bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        /**
288bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         * Run until shutdown of BT.
289bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         * Accept incoming connections and reject if needed. Keep accepting incoming connections.
290bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         */
291bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        @Override
292bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        public void run() {
293bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            try {
294bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                while (!mStopped) {
295bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    BluetoothSocket connSocket;
296bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    BluetoothDevice device;
297bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
298bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    try {
299bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        if (D) Log.d(TAG, "Accepting socket connection...");
300bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
301bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        connSocket = mServerSocket.accept();
302bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        if (D) Log.d(TAG, "Accepted socket connection from: " + mServerSocket);
303bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
304bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                       if (connSocket == null) {
305bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                           // TODO: Do we need a max error count, to avoid spinning?
306bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            Log.w(TAG, "connSocket is null - reattempt accept");
307bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            continue;
308bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        }
309bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        device = connSocket.getRemoteDevice();
310bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
311bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        if (device == null) {
312bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            Log.i(TAG, "getRemoteDevice() = null - reattempt accept");
313bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            try{
314bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                                connSocket.close();
315bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            } catch (IOException e) {
316bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                                Log.w(TAG, "Error closing the socket. ignoring...",e );
317bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            }
318bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            continue;
319bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        }
320bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
321bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        /* Signal to the service that we have received an incoming connection.
322bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                         */
323bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        boolean isValid = ObexServerSockets.this.onConnect(device, connSocket);
324bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
325bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        if(isValid == false) {
326bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            /* Close connection if we already have a connection with another device
327bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                             * by responding to the OBEX connect request.
328bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                             */
329bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            Log.i(TAG, "RemoteDevice is invalid - creating ObexRejectServer.");
330bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            BluetoothObexTransport obexTrans =
331bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                                    new BluetoothObexTransport(connSocket);
332bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            // Create and detach a selfdestructing ServerSession to respond to any
333bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            // incoming OBEX signals.
334bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            new ServerSession(obexTrans,
335bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                                    new ObexRejectServer(
336bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                                            ResponseCodes.OBEX_HTTP_UNAVAILABLE,
337bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                                            connSocket),
338bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                                    null);
339bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            // now wait for a new connect
340bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        } else {
341bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            // now wait for a new connect
342bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        }
343bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    } catch (IOException ex) {
344bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        if(mStopped == true) {
345bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            // Expected exception because of shutdown.
346bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        } else {
347bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            Log.w(TAG, "Accept exception for " +
348bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                                    mServerSocket, ex);
349bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                            ObexServerSockets.this.onAcceptFailed();
350bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        }
351bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                        mStopped=true;
352bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    }
353bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                } // End while()
354bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            } finally {
355bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                if (D) Log.d(TAG, "AcceptThread ended for: " + mServerSocket);
356bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            }
357bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
358bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
359bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        /**
360bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         * Shuts down the accept threads, and closes the ServerSockets, causing all related
361bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         * BluetoothSockets to disconnect, hence do not call until all all accepted connections
362bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         * are ready to be disconnected.
363bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde         */
364bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        public void shutdown() {
365bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            if(mStopped == false) {
366bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                mStopped = true;
367bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                // TODO: According to the documentation, this should not close the accepted
368bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                //       sockets - and that is true, but it closes the l2cap connections, and
369bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                //       therefore it implicitly also closes the accepted sockets...
370bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                try {
371bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                     mServerSocket.close();
372bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                } catch (IOException e) {
373bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                    if(D) Log.d(TAG, "Exception while thread shutdown:", e);
374bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                }
375bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            }
376bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            // If called from another thread, interrupt the thread
377bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            if(!Thread.currentThread().equals(this)){
378bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                // TODO: Will this interrupt the thread if it is blocked in synchronized?
379bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                // Else: change to use InterruptableLock
380bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                if(D) Log.d(TAG, "shutdown called from another thread - interrupt().");
381bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                interrupt();
382bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            }
383bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        }
384bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    }
385bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
386bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde}
387