• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothServerSocket;
21 import android.bluetooth.BluetoothSocket;
22 import android.os.Handler;
23 import android.os.Message;
24 import android.os.ParcelUuid;
25 import android.util.Log;
26 import android.util.SparseArray;
27 
28 import java.io.IOException;
29 import java.io.InterruptedIOException;
30 import java.lang.ref.WeakReference;
31 
32 import javax.obex.ServerSession;
33 
34 class BluetoothMnsService {
35 
36     private static final String TAG = "BluetoothMnsService";
37 
38     private static final ParcelUuid MAP_MNS =
39             ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
40 
41     static final int MSG_EVENT = 1;
42 
43     /* for BluetoothMasClient */
44     static final int EVENT_REPORT = 1001;
45 
46     /* these are shared across instances */
47     static private SparseArray<Handler> mCallbacks = null;
48     static private SocketAcceptThread mAcceptThread = null;
49     static private Handler mSessionHandler = null;
50     static private BluetoothServerSocket mServerSocket = null;
51 
52     private static class SessionHandler extends Handler {
53 
54         private final WeakReference<BluetoothMnsService> mService;
55 
SessionHandler(BluetoothMnsService service)56         SessionHandler(BluetoothMnsService service) {
57             mService = new WeakReference<BluetoothMnsService>(service);
58         }
59 
60         @Override
handleMessage(Message msg)61         public void handleMessage(Message msg) {
62             Log.d(TAG, "Handler: msg: " + msg.what);
63 
64             switch (msg.what) {
65                 case MSG_EVENT:
66                     int instanceId = msg.arg1;
67 
68                     synchronized (mCallbacks) {
69                         Handler cb = mCallbacks.get(instanceId);
70 
71                         if (cb != null) {
72                             BluetoothMapEventReport ev = (BluetoothMapEventReport) msg.obj;
73                             cb.obtainMessage(EVENT_REPORT, ev).sendToTarget();
74                         } else {
75                             Log.w(TAG, "Got event for instance which is not registered: "
76                                     + instanceId);
77                         }
78                     }
79                     break;
80             }
81         }
82     }
83 
84     private static class SocketAcceptThread extends Thread {
85 
86         private boolean mInterrupted = false;
87 
88         @Override
run()89         public void run() {
90 
91             if (mServerSocket != null) {
92                 Log.w(TAG, "Socket already created, exiting");
93                 return;
94             }
95 
96             try {
97                 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
98                 mServerSocket = adapter.listenUsingEncryptedRfcommWithServiceRecord(
99                         "MAP Message Notification Service", MAP_MNS.getUuid());
100             } catch (IOException e) {
101                 mInterrupted = true;
102                 Log.e(TAG, "I/O exception when trying to create server socket", e);
103             }
104 
105             while (!mInterrupted) {
106                 try {
107                     Log.v(TAG, "waiting to accept connection...");
108 
109                     BluetoothSocket sock = mServerSocket.accept();
110 
111                     Log.v(TAG, "new incoming connection from "
112                             + sock.getRemoteDevice().getName());
113 
114                     // session will live until closed by remote
115                     BluetoothMnsObexServer srv = new BluetoothMnsObexServer(mSessionHandler);
116                     BluetoothMapRfcommTransport transport = new BluetoothMapRfcommTransport(
117                             sock);
118                     new ServerSession(transport, srv, null);
119                 } catch (IOException ex) {
120                     Log.v(TAG, "I/O exception when waiting to accept (aborted?)");
121                     mInterrupted = true;
122                 }
123             }
124 
125             if (mServerSocket != null) {
126                 try {
127                     mServerSocket.close();
128                 } catch (IOException e) {
129                     // do nothing
130                 }
131 
132                 mServerSocket = null;
133             }
134         }
135     }
136 
BluetoothMnsService()137     BluetoothMnsService() {
138         Log.v(TAG, "BluetoothMnsService()");
139 
140         if (mCallbacks == null) {
141             Log.v(TAG, "BluetoothMnsService(): allocating callbacks");
142             mCallbacks = new SparseArray<Handler>();
143         }
144 
145         if (mSessionHandler == null) {
146             Log.v(TAG, "BluetoothMnsService(): allocating session handler");
147             mSessionHandler = new SessionHandler(this);
148         }
149     }
150 
registerCallback(int instanceId, Handler callback)151     public void registerCallback(int instanceId, Handler callback) {
152         Log.v(TAG, "registerCallback()");
153 
154         synchronized (mCallbacks) {
155             mCallbacks.put(instanceId, callback);
156 
157             if (mAcceptThread == null) {
158                 Log.v(TAG, "registerCallback(): starting MNS server");
159                 mAcceptThread = new SocketAcceptThread();
160                 mAcceptThread.setName("BluetoothMnsAcceptThread");
161                 mAcceptThread.start();
162             }
163         }
164     }
165 
unregisterCallback(int instanceId)166     public void unregisterCallback(int instanceId) {
167         Log.v(TAG, "unregisterCallback()");
168 
169         synchronized (mCallbacks) {
170             mCallbacks.remove(instanceId);
171 
172             if (mCallbacks.size() == 0) {
173                 Log.v(TAG, "unregisterCallback(): shutting down MNS server");
174 
175                 if (mServerSocket != null) {
176                     try {
177                         mServerSocket.close();
178                     } catch (IOException e) {
179                     }
180 
181                     mServerSocket = null;
182                 }
183 
184                 mAcceptThread.interrupt();
185 
186                 try {
187                     mAcceptThread.join(5000);
188                 } catch (InterruptedException e) {
189                 }
190 
191                 mAcceptThread = null;
192             }
193         }
194     }
195 }
196