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; 20d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwalimport android.os.HandlerThread; 21d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwalimport android.os.Looper; 22d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwalimport android.os.Message; 23192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.os.Process; 24192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.util.Log; 25192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 26192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport java.io.IOException; 27d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwalimport java.lang.ref.WeakReference; 28192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 29192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport javax.obex.ClientSession; 30192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport javax.obex.HeaderSet; 31192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport javax.obex.ObexTransport; 32192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport javax.obex.ResponseCodes; 33192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 34192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaclass BluetoothMasObexClientSession { 35192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta private static final String TAG = "BluetoothMasObexClientSession"; 36192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 37192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta private static final byte[] MAS_TARGET = new byte[] { 38192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta (byte) 0xbb, 0x58, 0x2b, 0x40, 0x42, 0x0c, 0x11, (byte) 0xdb, (byte) 0xb0, (byte) 0xde, 39192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 0x08, 0x00, 0x20, 0x0c, (byte) 0x9a, 0x66 40192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta }; 41192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 42d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private boolean DBG = true; 43d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal 44192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta static final int MSG_OBEX_CONNECTED = 100; 45192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta static final int MSG_OBEX_DISCONNECTED = 101; 46192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta static final int MSG_REQUEST_COMPLETED = 102; 47192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 48d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private static final int CONNECT = 0; 49d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private static final int DISCONNECT = 1; 50d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private static final int REQUEST = 2; 51d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal 52192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta private final ObexTransport mTransport; 53192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 54192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta private final Handler mSessionHandler; 55192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 56d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private ClientSession mSession; 57192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 58d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private HandlerThread mThread; 59d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private Handler mHandler; 60192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 61d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private boolean mConnected; 62192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 63d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private static class ObexClientHandler extends Handler { 64d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal WeakReference<BluetoothMasObexClientSession> mInst; 65192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 66d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal ObexClientHandler(Looper looper, BluetoothMasObexClientSession inst) { 67d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal super(looper); 68d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mInst = new WeakReference<BluetoothMasObexClientSession>(inst); 69d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 70192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 71d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal @Override 72d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal public void handleMessage(Message msg) { 73d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal BluetoothMasObexClientSession inst = mInst.get(); 74d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (!inst.connected() && msg.what != CONNECT) { 75d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal Log.w(TAG, "Cannot execute " + msg + " when not CONNECTED."); 76d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal return; 77d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 78192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 79d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal switch (msg.what) { 80d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal case CONNECT: 81d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal inst.connect(); 82d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal break; 83192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 84d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal case DISCONNECT: 85d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal inst.disconnect(); 86d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal break; 87192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 88d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal case REQUEST: 89d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal inst.executeRequest((BluetoothMasRequest) msg.obj); 90d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal break; 91d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 92d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 93d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 94192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 95d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal public BluetoothMasObexClientSession(ObexTransport transport, Handler handler) { 96d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mTransport = transport; 97d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mSessionHandler = handler; 98d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 99192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 100d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal public void start() { 101d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (DBG) Log.d(TAG, "start called."); 102d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (mConnected) { 103d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (DBG) Log.d(TAG, "Already connected, nothing to do."); 104d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal return; 105d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 106192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 107d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal // Start a thread to handle messages here. 108d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mThread = new HandlerThread("BluetoothMasObexClientSessionThread"); 109d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mThread.start(); 110d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mHandler = new ObexClientHandler(mThread.getLooper(), this); 111192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 112d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal // Connect it to the target device via OBEX. 113d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mHandler.obtainMessage(CONNECT).sendToTarget(); 114d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 115192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 116d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal public boolean makeRequest(BluetoothMasRequest request) { 117d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (DBG) Log.d(TAG, "makeRequest called with: " + request); 118d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal 119d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal boolean status = mHandler.sendMessage(mHandler.obtainMessage(REQUEST, request)); 120d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (!status) { 121d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal Log.e(TAG, "Adding messages failed, state: " + mConnected); 122d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal return false; 123192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 124d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal return true; 125d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 126192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 127d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal public void stop() { 128d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (DBG) Log.d(TAG, "stop called..."); 129192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 130d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mThread.quit(); 131d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal disconnect(); 132d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 133192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 134d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private void connect() { 135d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal try { 136d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mSession = new ClientSession(mTransport); 137192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 138d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal HeaderSet headerset = new HeaderSet(); 139d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal headerset.setHeader(HeaderSet.TARGET, MAS_TARGET); 140d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal 141d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal headerset = mSession.connect(headerset); 142d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal 143d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK) { 144d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mConnected = true; 145d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mSessionHandler.obtainMessage(MSG_OBEX_CONNECTED).sendToTarget(); 146d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } else { 147d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal disconnect(); 148192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 149d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } catch (IOException e) { 150d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal disconnect(); 151192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 152d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } 153192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 154d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private void disconnect() { 155d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (mSession != null) { 156192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta try { 157192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta mSession.disconnect(null); 158192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } catch (IOException e) { 159192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 160192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 161192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta try { 162192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta mSession.close(); 163192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } catch (IOException e) { 164192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 165192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 166192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 167d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mConnected = false; 168d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mSessionHandler.obtainMessage(MSG_OBEX_DISCONNECTED).sendToTarget(); 169192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 170192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 171d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private void executeRequest(BluetoothMasRequest request) { 172d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal try { 173d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal request.execute(mSession); 174d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal mSessionHandler.obtainMessage(MSG_REQUEST_COMPLETED, request).sendToTarget(); 175d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal } catch (IOException e) { 176d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal if (DBG) Log.d(TAG, "Request failed: " + request); 177192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 178d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal // Disconnect to cleanup. 179d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal disconnect(); 180192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 181192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 182192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 183192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta 184d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal private boolean connected() { 185d1ac8e05b6671626ac702ec57277689b7338bc32Sanket Agarwal return mConnected; 186192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta } 187192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta} 188