1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.bluetooth.client.map; 18 19import android.os.Handler; 20import android.os.HandlerThread; 21import android.os.Looper; 22import android.os.Message; 23import android.os.Process; 24import android.util.Log; 25 26import java.io.IOException; 27import java.lang.ref.WeakReference; 28 29import javax.obex.ClientSession; 30import javax.obex.HeaderSet; 31import javax.obex.ObexTransport; 32import javax.obex.ResponseCodes; 33 34class BluetoothMasObexClientSession { 35 private static final String TAG = "BluetoothMasObexClientSession"; 36 37 private static final byte[] MAS_TARGET = new byte[] { 38 (byte) 0xbb, 0x58, 0x2b, 0x40, 0x42, 0x0c, 0x11, (byte) 0xdb, (byte) 0xb0, (byte) 0xde, 39 0x08, 0x00, 0x20, 0x0c, (byte) 0x9a, 0x66 40 }; 41 42 private boolean DBG = true; 43 44 static final int MSG_OBEX_CONNECTED = 100; 45 static final int MSG_OBEX_DISCONNECTED = 101; 46 static final int MSG_REQUEST_COMPLETED = 102; 47 48 private static final int CONNECT = 0; 49 private static final int DISCONNECT = 1; 50 private static final int REQUEST = 2; 51 52 private final ObexTransport mTransport; 53 54 private final Handler mSessionHandler; 55 56 private ClientSession mSession; 57 58 private HandlerThread mThread; 59 private Handler mHandler; 60 61 private boolean mConnected; 62 63 private static class ObexClientHandler extends Handler { 64 WeakReference<BluetoothMasObexClientSession> mInst; 65 66 ObexClientHandler(Looper looper, BluetoothMasObexClientSession inst) { 67 super(looper); 68 mInst = new WeakReference<BluetoothMasObexClientSession>(inst); 69 } 70 71 @Override 72 public void handleMessage(Message msg) { 73 BluetoothMasObexClientSession inst = mInst.get(); 74 if (!inst.connected() && msg.what != CONNECT) { 75 Log.w(TAG, "Cannot execute " + msg + " when not CONNECTED."); 76 return; 77 } 78 79 switch (msg.what) { 80 case CONNECT: 81 inst.connect(); 82 break; 83 84 case DISCONNECT: 85 inst.disconnect(); 86 break; 87 88 case REQUEST: 89 inst.executeRequest((BluetoothMasRequest) msg.obj); 90 break; 91 } 92 } 93 } 94 95 public BluetoothMasObexClientSession(ObexTransport transport, Handler handler) { 96 mTransport = transport; 97 mSessionHandler = handler; 98 } 99 100 public void start() { 101 if (DBG) Log.d(TAG, "start called."); 102 if (mConnected) { 103 if (DBG) Log.d(TAG, "Already connected, nothing to do."); 104 return; 105 } 106 107 // Start a thread to handle messages here. 108 mThread = new HandlerThread("BluetoothMasObexClientSessionThread"); 109 mThread.start(); 110 mHandler = new ObexClientHandler(mThread.getLooper(), this); 111 112 // Connect it to the target device via OBEX. 113 mHandler.obtainMessage(CONNECT).sendToTarget(); 114 } 115 116 public boolean makeRequest(BluetoothMasRequest request) { 117 if (DBG) Log.d(TAG, "makeRequest called with: " + request); 118 119 boolean status = mHandler.sendMessage(mHandler.obtainMessage(REQUEST, request)); 120 if (!status) { 121 Log.e(TAG, "Adding messages failed, state: " + mConnected); 122 return false; 123 } 124 return true; 125 } 126 127 public void stop() { 128 if (DBG) Log.d(TAG, "stop called..."); 129 130 mThread.quit(); 131 disconnect(); 132 } 133 134 private void connect() { 135 try { 136 mSession = new ClientSession(mTransport); 137 138 HeaderSet headerset = new HeaderSet(); 139 headerset.setHeader(HeaderSet.TARGET, MAS_TARGET); 140 141 headerset = mSession.connect(headerset); 142 143 if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK) { 144 mConnected = true; 145 mSessionHandler.obtainMessage(MSG_OBEX_CONNECTED).sendToTarget(); 146 } else { 147 disconnect(); 148 } 149 } catch (IOException e) { 150 disconnect(); 151 } 152 } 153 154 private void disconnect() { 155 if (mSession != null) { 156 try { 157 mSession.disconnect(null); 158 } catch (IOException e) { 159 } 160 161 try { 162 mSession.close(); 163 } catch (IOException e) { 164 } 165 } 166 167 mConnected = false; 168 mSessionHandler.obtainMessage(MSG_OBEX_DISCONNECTED).sendToTarget(); 169 } 170 171 private void executeRequest(BluetoothMasRequest request) { 172 try { 173 request.execute(mSession); 174 mSessionHandler.obtainMessage(MSG_REQUEST_COMPLETED, request).sendToTarget(); 175 } catch (IOException e) { 176 if (DBG) Log.d(TAG, "Request failed: " + request); 177 178 // Disconnect to cleanup. 179 disconnect(); 180 } 181 } 182 183 184 private boolean connected() { 185 return mConnected; 186 } 187} 188