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 17 package android.bluetooth.client.map; 18 19 import android.os.Handler; 20 import android.os.Process; 21 import android.util.Log; 22 23 import java.io.IOException; 24 25 import javax.obex.ClientSession; 26 import javax.obex.HeaderSet; 27 import javax.obex.ObexTransport; 28 import javax.obex.ResponseCodes; 29 30 class BluetoothMasObexClientSession { 31 private static final String TAG = "BluetoothMasObexClientSession"; 32 33 private static final byte[] MAS_TARGET = new byte[] { 34 (byte) 0xbb, 0x58, 0x2b, 0x40, 0x42, 0x0c, 0x11, (byte) 0xdb, (byte) 0xb0, (byte) 0xde, 35 0x08, 0x00, 0x20, 0x0c, (byte) 0x9a, 0x66 36 }; 37 38 static final int MSG_OBEX_CONNECTED = 100; 39 static final int MSG_OBEX_DISCONNECTED = 101; 40 static final int MSG_REQUEST_COMPLETED = 102; 41 42 private final ObexTransport mTransport; 43 44 private final Handler mSessionHandler; 45 46 private ClientThread mClientThread; 47 48 private volatile boolean mInterrupted; 49 50 private class ClientThread extends Thread { 51 private final ObexTransport mTransport; 52 53 private ClientSession mSession; 54 55 private BluetoothMasRequest mRequest; 56 57 private boolean mConnected; 58 59 public ClientThread(ObexTransport transport) { 60 super("MAS ClientThread"); 61 62 mTransport = transport; 63 mConnected = false; 64 } 65 66 @Override 67 public void run() { 68 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 69 70 connect(); 71 72 if (mConnected) { 73 mSessionHandler.obtainMessage(MSG_OBEX_CONNECTED).sendToTarget(); 74 } else { 75 mSessionHandler.obtainMessage(MSG_OBEX_DISCONNECTED).sendToTarget(); 76 return; 77 } 78 79 while (!mInterrupted) { 80 synchronized (this) { 81 if (mRequest == null) { 82 try { 83 this.wait(); 84 } catch (InterruptedException e) { 85 mInterrupted = true; 86 } 87 } 88 } 89 90 if (!mInterrupted && mRequest != null) { 91 try { 92 mRequest.execute(mSession); 93 } catch (IOException e) { 94 // this will "disconnect" to cleanup 95 mInterrupted = true; 96 } 97 98 BluetoothMasRequest oldReq = mRequest; 99 mRequest = null; 100 101 mSessionHandler.obtainMessage(MSG_REQUEST_COMPLETED, oldReq).sendToTarget(); 102 } 103 } 104 105 disconnect(); 106 107 mSessionHandler.obtainMessage(MSG_OBEX_DISCONNECTED).sendToTarget(); 108 } 109 110 private void connect() { 111 try { 112 mSession = new ClientSession(mTransport); 113 114 HeaderSet headerset = new HeaderSet(); 115 headerset.setHeader(HeaderSet.TARGET, MAS_TARGET); 116 117 headerset = mSession.connect(headerset); 118 119 if (headerset.getResponseCode() == ResponseCodes.OBEX_HTTP_OK) { 120 mConnected = true; 121 } else { 122 disconnect(); 123 } 124 } catch (IOException e) { 125 } 126 } 127 128 private void disconnect() { 129 try { 130 mSession.disconnect(null); 131 } catch (IOException e) { 132 } 133 134 try { 135 mSession.close(); 136 } catch (IOException e) { 137 } 138 139 mConnected = false; 140 } 141 142 public synchronized boolean schedule(BluetoothMasRequest request) { 143 if (mRequest != null) { 144 return false; 145 } 146 147 mRequest = request; 148 notify(); 149 150 return true; 151 } 152 } 153 154 public BluetoothMasObexClientSession(ObexTransport transport, Handler handler) { 155 mTransport = transport; 156 mSessionHandler = handler; 157 } 158 159 public void start() { 160 if (mClientThread == null) { 161 mClientThread = new ClientThread(mTransport); 162 mClientThread.start(); 163 } 164 165 } 166 167 public void stop() { 168 if (mClientThread != null) { 169 mClientThread.interrupt(); 170 171 (new Thread() { 172 @Override 173 public void run() { 174 try { 175 mClientThread.join(); 176 mClientThread = null; 177 } catch (InterruptedException e) { 178 Log.w(TAG, "Interrupted while waiting for thread to join"); 179 } 180 } 181 }).run(); 182 } 183 } 184 185 public boolean makeRequest(BluetoothMasRequest request) { 186 if (mClientThread == null) { 187 return false; 188 } 189 190 return mClientThread.schedule(request); 191 } 192 } 193