1b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo/*
2b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo * Copyright (C) 2016 The Android Open Source Project
3b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo *
4b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo * Licensed under the Apache License, Version 2.0 (the "License");
5b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo * you may not use this file except in compliance with the License.
6b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo * You may obtain a copy of the License at
7b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo *
8b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo *      http://www.apache.org/licenses/LICENSE-2.0
9b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo *
10b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo * Unless required by applicable law or agreed to in writing, software
11b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo * distributed under the License is distributed on an "AS IS" BASIS,
12b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo * See the License for the specific language governing permissions and
14b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo * limitations under the License.
15b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo */
16b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
17b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzopackage com.android.bluetooth.pbapclient;
18b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
19b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport android.bluetooth.BluetoothAdapter;
20b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport android.bluetooth.BluetoothDevice;
21b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport android.bluetooth.BluetoothSocket;
22b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport android.os.Handler;
23b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport android.os.Handler.Callback;
24b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport android.os.HandlerThread;
25b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport android.os.Message;
26b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport android.os.Process;
27b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport android.util.Log;
28b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
29b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport java.io.IOException;
30b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoimport java.util.UUID;
31b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
32b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzoclass BluetoothPbapSession implements Callback {
33b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    //TODO consider cleaning file organization and naming.
34b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private static final String TAG = "com.android.bluetooth.pbapclient.BluetoothPbapSession";
35b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
36b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    /* local use only */
37b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private static final int RFCOMM_CONNECTED = 1;
38b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private static final int RFCOMM_FAILED = 2;
39b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
40b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    /* to BluetoothPbapClient */
41b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int REQUEST_COMPLETED = 3;
42b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int REQUEST_FAILED = 4;
43b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int SESSION_CONNECTING = 5;
44b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int SESSION_CONNECTED = 6;
45b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int SESSION_DISCONNECTED = 7;
46b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int AUTH_REQUESTED = 8;
47b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int AUTH_TIMEOUT = 9;
48b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
49b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int ACTION_LISTING = 14;
50b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int ACTION_VCARD = 15;
51b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public static final int ACTION_PHONEBOOK_SIZE = 16;
52b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
53b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private static final String PBAP_UUID =
54b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            "0000112f-0000-1000-8000-00805f9b34fb";
55b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
56b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private final BluetoothAdapter mAdapter;
57b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private final BluetoothDevice mDevice;
58b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
59b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private final Handler mParentHandler;
60b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
61b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private final HandlerThread mHandlerThread;
62b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private final Handler mSessionHandler;
63b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
64b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private RfcommConnectThread mConnectThread;
65b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private BluetoothPbapObexTransport mTransport;
66b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
67b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private BluetoothPbapObexSession mObexSession;
68b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
69b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private BluetoothPbapRequest mPendingRequest = null;
70b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
71b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public BluetoothPbapSession(BluetoothDevice device, Handler handler) {
72b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
73b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mAdapter = BluetoothAdapter.getDefaultAdapter();
74b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mAdapter == null) {
75b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            throw new NullPointerException("No Bluetooth adapter in the system");
76b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
77b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
78b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mDevice = device;
79b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mParentHandler = handler;
80b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mConnectThread = null;
81b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mTransport = null;
82b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mObexSession = null;
83b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
84b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mHandlerThread = new HandlerThread("PBAP session handler",
85b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                Process.THREAD_PRIORITY_BACKGROUND);
86b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mHandlerThread.start();
87b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mSessionHandler = new Handler(mHandlerThread.getLooper(), this);
88b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
89b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
90b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    @Override
91b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public boolean handleMessage(Message msg) {
92b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.d(TAG, "Handler: msg: " + msg.what);
93b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
94b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        switch (msg.what) {
95b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            case RFCOMM_FAILED:
96b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mConnectThread = null;
97b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
98b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mParentHandler.obtainMessage(SESSION_DISCONNECTED).sendToTarget();
99b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
100b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                if (mPendingRequest != null) {
101b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                    mParentHandler.obtainMessage(REQUEST_FAILED, mPendingRequest).sendToTarget();
102b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                    mPendingRequest = null;
103b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                }
104b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                break;
105b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
106b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            case RFCOMM_CONNECTED:
107b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mConnectThread = null;
108b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mTransport = (BluetoothPbapObexTransport) msg.obj;
109b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                startObexSession();
110b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                break;
111b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
112b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            case BluetoothPbapObexSession.OBEX_SESSION_FAILED:
113b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                stopObexSession();
114b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
115b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mParentHandler.obtainMessage(SESSION_DISCONNECTED).sendToTarget();
116b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
117b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                if (mPendingRequest != null) {
118b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                    mParentHandler.obtainMessage(REQUEST_FAILED, mPendingRequest).sendToTarget();
119b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                    mPendingRequest = null;
120b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                }
121b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                break;
122b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
123b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            case BluetoothPbapObexSession.OBEX_SESSION_CONNECTED:
124b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mParentHandler.obtainMessage(SESSION_CONNECTED).sendToTarget();
125b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
126b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                if (mPendingRequest != null) {
127b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                    mObexSession.schedule(mPendingRequest);
128b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                    mPendingRequest = null;
129b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                }
130b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                break;
131b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
132b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            case BluetoothPbapObexSession.OBEX_SESSION_DISCONNECTED:
133b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mParentHandler.obtainMessage(SESSION_DISCONNECTED).sendToTarget();
134b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                stopRfcomm();
135b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                break;
136b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
137b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            case BluetoothPbapObexSession.OBEX_SESSION_REQUEST_COMPLETED:
138b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                /* send to parent, process there */
139b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mParentHandler.obtainMessage(REQUEST_COMPLETED, msg.obj).sendToTarget();
140b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                break;
141b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
142b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            case BluetoothPbapObexSession.OBEX_SESSION_REQUEST_FAILED:
143b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                /* send to parent, process there */
144b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mParentHandler.obtainMessage(REQUEST_FAILED, msg.obj).sendToTarget();
145b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                break;
146b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
147b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            case BluetoothPbapObexSession.OBEX_SESSION_AUTHENTICATION_REQUEST:
148b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                /* send to parent, process there */
149b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mParentHandler.obtainMessage(AUTH_REQUESTED).sendToTarget();
150b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
151b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mSessionHandler
152b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                        .sendMessageDelayed(
153b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                                mSessionHandler
154b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                                        .obtainMessage(BluetoothPbapObexSession.OBEX_SESSION_AUTHENTICATION_TIMEOUT),
155b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                                30000);
156b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                break;
157b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
158b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            case BluetoothPbapObexSession.OBEX_SESSION_AUTHENTICATION_TIMEOUT:
159b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                /* stop authentication */
160b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                setAuthResponse(null);
161b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
162b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mParentHandler.obtainMessage(AUTH_TIMEOUT).sendToTarget();
163b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                break;
164b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
165b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            default:
166b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                return false;
167b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
168b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
169b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        return true;
170b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
171b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
172b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public void start() {
173b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.d(TAG, "start");
174b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
175b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        startRfcomm();
176b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
177b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
178b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public void stop() {
179b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.d(TAG, "Stop");
180b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
181b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        stopObexSession();
182b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        stopRfcomm();
183b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
184b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
185b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public void abort() {
186b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.d(TAG, "abort");
187b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
188b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        /* fail pending request immediately */
189b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mPendingRequest != null) {
190b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mParentHandler.obtainMessage(REQUEST_FAILED, mPendingRequest).sendToTarget();
191b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mPendingRequest = null;
192b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
193b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
194b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mObexSession != null) {
195b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mObexSession.abort();
196b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
197b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
198b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
199b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public boolean makeRequest(BluetoothPbapRequest request) {
200b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.v(TAG, "makeRequest: " + request.getClass().getSimpleName());
201b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
202b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mPendingRequest != null) {
203b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            Log.w(TAG, "makeRequest: request already queued, exiting");
204b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            return false;
205b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
206b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
207b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mObexSession == null) {
208b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mPendingRequest = request;
209b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
210b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            /*
211b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo             * since there is no pending request and no session it's safe to
212b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo             * assume that RFCOMM does not exist either and we should start
213b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo             * connecting it
214b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo             */
215b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            startRfcomm();
216b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
217b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            return true;
218b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
219b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
220b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        return mObexSession.schedule(request);
221b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
222b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
223b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    public boolean setAuthResponse(String key) {
224b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.d(TAG, "setAuthResponse key=" + key);
225b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
226b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mSessionHandler
227b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                .removeMessages(BluetoothPbapObexSession.OBEX_SESSION_AUTHENTICATION_TIMEOUT);
228b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
229b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        /* does not make sense to set auth response when OBEX session is down */
230b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mObexSession == null) {
231b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            return false;
232b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
233b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
234b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        return mObexSession.setAuthReply(key);
235b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
236b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
237b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private void startRfcomm() {
238b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.d(TAG, "startRfcomm");
239b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
240b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mConnectThread == null && mObexSession == null) {
241b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mParentHandler.obtainMessage(SESSION_CONNECTING).sendToTarget();
242b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
243b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mConnectThread = new RfcommConnectThread();
244b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mConnectThread.start();
245b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
246b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
247b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        /*
248b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo         * don't care if mConnectThread is not null - it means RFCOMM is being
249b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo         * connected anyway
250b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo         */
251b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
252b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
253b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private void stopRfcomm() {
254b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.d(TAG, "stopRfcomm");
255b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
256b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mConnectThread != null) {
257b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            try {
258b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                // Force close the socket in case the thread is stuck doing the connect()
259b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                // call.
260b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mConnectThread.closeSocket();
261b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                // TODO: Add timed join if closeSocket does not clean up the state.
262b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mConnectThread.join();
263b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            } catch (InterruptedException e) {
264b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            }
265b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
266b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mConnectThread = null;
267b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
268b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
269b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mTransport != null) {
270b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            try {
271b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mTransport.close();
272b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            } catch (IOException e) {
273b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            }
274b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
275b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mTransport = null;
276b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
277b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
278b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
279b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private void startObexSession() {
280b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.d(TAG, "startObexSession");
281b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
282b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mObexSession = new BluetoothPbapObexSession(mTransport);
283b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        mObexSession.start(mSessionHandler);
284b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
285b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
286b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private void stopObexSession() {
287b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        Log.d(TAG, "stopObexSession");
288b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
289b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        if (mObexSession != null) {
290b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mObexSession.stop();
291b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            mObexSession = null;
292b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
293b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
294b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
295b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    private class RfcommConnectThread extends Thread {
296b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        private static final String TAG = "RfcommConnectThread";
297b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
298b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        private BluetoothSocket mSocket;
299b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
300b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        public RfcommConnectThread() {
301b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            super("RfcommConnectThread");
302b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
303b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
304b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        @Override
305b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        public void run() {
306b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            if (mAdapter.isDiscovering()) {
307b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mAdapter.cancelDiscovery();
308b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            }
309b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
310b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            try {
311b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mSocket = mDevice.createRfcommSocketToServiceRecord(UUID.fromString(PBAP_UUID));
312b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mSocket.connect();
313b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
314b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                BluetoothPbapObexTransport transport;
315b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                transport = new BluetoothPbapObexTransport(mSocket);
316b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
317b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mSessionHandler.obtainMessage(RFCOMM_CONNECTED, transport).sendToTarget();
318b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            } catch (IOException e) {
319b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                closeSocket();
320b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                mSessionHandler.obtainMessage(RFCOMM_FAILED).sendToTarget();
321b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            }
322b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
323b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
324b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo
325b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        // This method may be called from outside the thread if the connect() call above is stuck.
326b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        public void closeSocket() {
327b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            try {
328b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                if (mSocket != null) {
329b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                    mSocket.close();
330b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                }
331b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            } catch (IOException e) {
332b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo                Log.e(TAG, "Error when closing socket", e);
333b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo            }
334b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo        }
335b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo    }
336b874a1d1cf25f90947ba87f791d42a404cad7d85Joseph Pirozzo}
337