1192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta/*
2192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Copyright (C) 2014 The Android Open Source Project
3192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *
4192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Licensed under the Apache License, Version 2.0 (the "License");
5192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * you may not use this file except in compliance with the License.
6192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * You may obtain a copy of the License at
7192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *
8192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *      http://www.apache.org/licenses/LICENSE-2.0
9192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *
10192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Unless required by applicable law or agreed to in writing, software
11192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * distributed under the License is distributed on an "AS IS" BASIS,
12192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * See the License for the specific language governing permissions and
14192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * limitations under the License.
15192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta */
16192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
17192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptapackage android.bluetooth.client.map;
18192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
19192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.os.Handler;
20192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.os.Process;
21192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.util.Log;
22192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
23192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport java.io.IOException;
24192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
25192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport javax.obex.ClientSession;
26192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport javax.obex.HeaderSet;
27192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport javax.obex.ObexTransport;
28192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport javax.obex.ResponseCodes;
29192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
30192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaclass BluetoothMasObexClientSession {
31192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private static final String TAG = "BluetoothMasObexClientSession";
32192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
33192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private static final byte[] MAS_TARGET = new byte[] {
34192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            (byte) 0xbb, 0x58, 0x2b, 0x40, 0x42, 0x0c, 0x11, (byte) 0xdb, (byte) 0xb0, (byte) 0xde,
35192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            0x08, 0x00, 0x20, 0x0c, (byte) 0x9a, 0x66
36192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    };
37192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
38192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    static final int MSG_OBEX_CONNECTED = 100;
39192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    static final int MSG_OBEX_DISCONNECTED = 101;
40192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    static final int MSG_REQUEST_COMPLETED = 102;
41192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
42192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final ObexTransport mTransport;
43192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
44192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final Handler mSessionHandler;
45192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
46192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private ClientThread mClientThread;
47192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
48192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private volatile boolean mInterrupted;
49192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
50192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private class ClientThread extends Thread {
51192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        private final ObexTransport mTransport;
52192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
53192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        private ClientSession mSession;
54192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
55192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        private BluetoothMasRequest mRequest;
56192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
57192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        private boolean mConnected;
58192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
59192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        public ClientThread(ObexTransport transport) {
60192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            super("MAS ClientThread");
61192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
62192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mTransport = transport;
63192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mConnected = false;
64192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
65192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
66192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        @Override
67192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        public void run() {
68192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
69192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
70192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            connect();
71192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
72192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if (mConnected) {
73192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mSessionHandler.obtainMessage(MSG_OBEX_CONNECTED).sendToTarget();
74192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } else {
75192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mSessionHandler.obtainMessage(MSG_OBEX_DISCONNECTED).sendToTarget();
76192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                return;
77192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
78192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
79192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            while (!mInterrupted) {
80192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                synchronized (this) {
81192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    if (mRequest == null) {
82192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        try {
83192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                            this.wait();
84192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        } catch (InterruptedException e) {
85192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                            mInterrupted = true;
86192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        }
87192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    }
88192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                }
89192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
90192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                if (!mInterrupted && mRequest != null) {
91192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    try {
92192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        mRequest.execute(mSession);
93192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    } catch (IOException e) {
94192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        // this will "disconnect" to cleanup
95192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        mInterrupted = true;
96192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    }
97192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
98192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    BluetoothMasRequest oldReq = mRequest;
99192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    mRequest = null;
100192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
101192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    mSessionHandler.obtainMessage(MSG_REQUEST_COMPLETED, oldReq).sendToTarget();
102192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                }
103192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
104192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
105192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            disconnect();
106192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
107192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mSessionHandler.obtainMessage(MSG_OBEX_DISCONNECTED).sendToTarget();
108192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
109192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
110192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        private void connect() {
111192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            try {
112192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mSession = new ClientSession(mTransport);
113192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
114192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                HeaderSet headerset = new HeaderSet();
115192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                headerset.setHeader(HeaderSet.TARGET, MAS_TARGET);
116192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
117192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                headerset = mSession.connect(headerset);
118192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
119192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK) {
120192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    mConnected = true;
121192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                } else {
122192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    disconnect();
123192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                }
124192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } catch (IOException e) {
125192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
126192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
127192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
128192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        private void disconnect() {
129192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            try {
130192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mSession.disconnect(null);
131192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } catch (IOException e) {
132192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
133192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
134192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            try {
135192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mSession.close();
136192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } catch (IOException e) {
137192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
138192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
139192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mConnected = false;
140192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
141192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
142192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        public synchronized boolean schedule(BluetoothMasRequest request) {
143192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if (mRequest != null) {
144192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                return false;
145192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
146192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
147192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mRequest = request;
148192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            notify();
149192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
150192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            return true;
151192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
152192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
153192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
154192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public BluetoothMasObexClientSession(ObexTransport transport, Handler handler) {
155192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        mTransport = transport;
156192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        mSessionHandler = handler;
157192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
158192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
159192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public void start() {
160192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (mClientThread == null) {
161192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mClientThread = new ClientThread(mTransport);
162192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mClientThread.start();
163192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
164192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
165192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
166192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
167192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public void stop() {
168192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (mClientThread != null) {
169192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mClientThread.interrupt();
170192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
171192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            (new Thread() {
172192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                @Override
173192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                public void run() {
174192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    try {
175192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        mClientThread.join();
176192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        mClientThread = null;
177192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    } catch (InterruptedException e) {
178192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        Log.w(TAG, "Interrupted while waiting for thread to join");
179192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    }
180192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                }
181192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }).run();
182192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
183192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
184192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
185192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public boolean makeRequest(BluetoothMasRequest request) {
186192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (mClientThread == null) {
187192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            return false;
188192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
189192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
190192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return mClientThread.schedule(request);
191192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
192192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta}
193