1326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde/* 2326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* Copyright (C) 2014 Samsung System LSI 3326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* Licensed under the Apache License, Version 2.0 (the "License"); 4326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* you may not use this file except in compliance with the License. 5326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* You may obtain a copy of the License at 6326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* 7326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* http://www.apache.org/licenses/LICENSE-2.0 8326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* 9326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* Unless required by applicable law or agreed to in writing, software 10326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* distributed under the License is distributed on an "AS IS" BASIS, 11326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* See the License for the specific language governing permissions and 13326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* limitations under the License. 14326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde*/ 15326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondepackage com.android.bluetooth.map; 16326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 17326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.io.IOException; 18326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 19326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport javax.obex.ServerSession; 20326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 21326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.bluetooth.BluetoothAdapter; 22326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.bluetooth.BluetoothDevice; 23326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.bluetooth.BluetoothServerSocket; 24326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.bluetooth.BluetoothSocket; 25326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.bluetooth.BluetoothUuid; 26326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.content.Context; 27326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.content.Intent; 28326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.os.Handler; 29326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.os.RemoteException; 30326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.util.Log; 31326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 32326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondepublic class BluetoothMapMasInstance { 33326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final String TAG = "BluetoothMapMasInstance"; 34326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 35326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final boolean D = BluetoothMapService.DEBUG; 36326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final boolean V = BluetoothMapService.VERBOSE; 37326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 38326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final int SDP_MAP_MSG_TYPE_EMAIL = 0x01; 39326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final int SDP_MAP_MSG_TYPE_SMS_GSM = 0x02; 40326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final int SDP_MAP_MSG_TYPE_SMS_CDMA = 0x04; 41326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private static final int SDP_MAP_MSG_TYPE_MMS = 0x08; 42326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 43326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private SocketAcceptThread mAcceptThread = null; 44326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 45326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private ServerSession mServerSession = null; 46326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 47326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // The handle to the socket registration with SDP 48326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private BluetoothServerSocket mServerSocket = null; 49326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 50326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // The actual incoming connection handle 51326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private BluetoothSocket mConnSocket = null; 52326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 53326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private BluetoothDevice mRemoteDevice = null; // The remote connected device 54326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 55326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private BluetoothAdapter mAdapter; 56326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 57326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private volatile boolean mInterrupted; // Used to interrupt socket accept thread 58326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 59326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private Handler mServiceHandler = null; // MAP service message handler 60326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private BluetoothMapService mMapService = null; // Handle to the outer MAP service 61326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private Context mContext = null; // MAP service context 62326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private BluetoothMnsObexClient mMnsClient = null; // Shared MAP MNS client 63326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private BluetoothMapEmailSettingsItem mAccount = null; // 64326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private String mBaseEmailUri = null; // Email client base URI for this instance 65326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private int mMasInstanceId = -1; 66326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private boolean mEnableSmsMms = false; 67326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde BluetoothMapContentObserver mObserver; 68326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 69326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 70326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Create a e-mail MAS instance 71326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param callback 72326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param context 73326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param mns 74326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @param emailBaseUri - use null to create a SMS/MMS MAS instance 75326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 76326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public BluetoothMapMasInstance (BluetoothMapService mapService, 77326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Context context, 78326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde BluetoothMapEmailSettingsItem account, 79326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde int masId, 80326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde boolean enableSmsMms) { 81326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mMapService = mapService; 82326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mServiceHandler = mapService.getHandler(); 83326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mContext = context; 84326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAccount = account; 85326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(account != null) { 86326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mBaseEmailUri = account.mBase_uri; 87326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 88326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mMasInstanceId = masId; 89326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mEnableSmsMms = enableSmsMms; 90326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde init(); 91326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 92326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 93326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 94326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public String toString() { 95326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return "MasId: " + mMasInstanceId + " Uri:" + mBaseEmailUri + " SMS/MMS:" + mEnableSmsMms; 96326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 97326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 98326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private void init() { 99326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAdapter = BluetoothAdapter.getDefaultAdapter(); 100326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 101326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 102326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public int getMasId() { 103326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mMasInstanceId; 104326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 105326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 106326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 107326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * A thread that runs in the background waiting for remote rfcomm 108326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * connect. Once a remote socket connected, this thread shall be 109326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * shutdown. When the remote disconnect, this thread shall run again 110326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * waiting for next request. 111326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 112326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private class SocketAcceptThread extends Thread { 113326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 114326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private boolean stopped = false; 115326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 116326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde @Override 117326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public void run() { 118326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde BluetoothServerSocket serverSocket; 119326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mServerSocket == null) { 120326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (!initSocket()) { 121326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return; 122326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 123326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 124326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 125326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde while (!stopped) { 126326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 127326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, "Accepting socket connection..."); 128326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde serverSocket = mServerSocket; 129326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(serverSocket == null) { 130326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, "mServerSocket is null"); 131326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde break; 132326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 133326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mConnSocket = serverSocket.accept(); 134326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, "Accepted socket connection..."); 135326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 136326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde synchronized (BluetoothMapMasInstance.this) { 137326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mConnSocket == null) { 138326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, "mConnSocket is null"); 139326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde break; 140326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 141326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mRemoteDevice = mConnSocket.getRemoteDevice(); 142326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 143326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 144326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mRemoteDevice == null) { 145326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.i(TAG, "getRemoteDevice() = null"); 146326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde break; 147326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 148326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 149326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /* Signal to the service that we have received an incoming connection. 150326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 151326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde boolean isValid = mMapService.onConnect(mRemoteDevice, BluetoothMapMasInstance.this); 152326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 153326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(isValid == false) { 154326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // Close connection if we already have a connection with another device 155326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.i(TAG, "RemoteDevice is invalid - closing."); 156326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mConnSocket.close(); 157326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mConnSocket = null; 158326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // now wait for a new connect 159326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 160326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde stopped = true; // job done ,close this thread; 161326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 162326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException ex) { 163326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde stopped=true; 164326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.v(TAG, "Accept exception: (expected at shutdown)", ex); 165326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 166326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 167326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 168326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 169326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde void shutdown() { 170326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde stopped = true; 171326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mServerSocket != null) { 172326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 173326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mServerSocket.close(); 174326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 175326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(D) Log.d(TAG, "Exception while thread shurdown:", e); 176326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 177326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mServerSocket = null; 178326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 179326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 180326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde interrupt(); 181326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 182326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 183326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 184326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public void startRfcommSocketListener() { 185326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, "Map Service startRfcommSocketListener"); 186326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mInterrupted = false; /* For this to work all calls to this function 187326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde and shutdown() must be from same thread. */ 188326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mAcceptThread == null) { 189326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAcceptThread = new SocketAcceptThread(); 190326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAcceptThread.setName("BluetoothMapAcceptThread masId=" + mMasInstanceId); 191326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAcceptThread.start(); 192326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 193326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 194326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 195326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private final boolean initSocket() { 196326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, "MAS initSocket()"); 197326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 198326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde boolean initSocketOK = false; 199326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde final int CREATE_RETRY_TIME = 10; 200326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 201326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // It's possible that create will fail in some cases. retry for 10 times 202326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde for (int i = 0; (i < CREATE_RETRY_TIME) && !mInterrupted; i++) { 203326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde initSocketOK = true; 204326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 205326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // It is mandatory for MSE to support initiation of bonding and 206326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // encryption. 207326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String masId = String.format("%02x", mMasInstanceId & 0xff); 208326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String masName = ""; 209326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde int messageTypeFlags = 0; 210326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mEnableSmsMms) { 211326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde masName = "SMS/MMS"; 212326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde messageTypeFlags |= SDP_MAP_MSG_TYPE_SMS_GSM | 213326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde SDP_MAP_MSG_TYPE_SMS_CDMA| 214326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde SDP_MAP_MSG_TYPE_MMS; 215326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 216326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mBaseEmailUri != null) { 217326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mEnableSmsMms) { 218326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde masName += "/EMAIL"; 219326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 220326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde masName = mAccount.getName(); 221326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 222326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde messageTypeFlags |= SDP_MAP_MSG_TYPE_EMAIL; 223326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 224326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String msgTypes = String.format("%02x", messageTypeFlags & 0xff); 225326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde String sdpString = masId + msgTypes + masName; 226326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(V) Log.d(TAG, " masId = " + masId + 227326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde "\n msgTypes = " + msgTypes + 228326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde "\n masName = " + masName + 229326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde "\n SDP string = " + sdpString); 230326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mServerSocket = mAdapter.listenUsingRfcommWithServiceRecord 231326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde (sdpString, BluetoothUuid.MAS.getUuid()); 232326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 233326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 234326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.e(TAG, "Error create RfcommServerSocket " + e.toString()); 235326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde initSocketOK = false; 236326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 237326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (!initSocketOK) { 238326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // Need to break out of this loop if BT is being turned off. 239326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mAdapter == null) break; 240326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde int state = mAdapter.getState(); 241326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if ((state != BluetoothAdapter.STATE_TURNING_ON) && 242326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde (state != BluetoothAdapter.STATE_ON)) { 243326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.w(TAG, "initServerSocket failed as BT is (being) turned off"); 244326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde break; 245326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 246326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 247326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (V) Log.v(TAG, "waiting 300 ms..."); 248326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Thread.sleep(300); 249326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (InterruptedException e) { 250326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.e(TAG, "socketAcceptThread thread was interrupted (3)"); 251326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 252326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 253326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde break; 254326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 255326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 256326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mInterrupted) { 257326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde initSocketOK = false; 258326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // close server socket to avoid resource leakage 259326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde closeServerSocket(); 260326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 261326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 262326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (initSocketOK) { 263326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (V) Log.v(TAG, "Succeed to create listening socket "); 264326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 265326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } else { 266326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.e(TAG, "Error to create listening socket after " + CREATE_RETRY_TIME + " try"); 267326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 268326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return initSocketOK; 269326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 270326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 271326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /* Called for all MAS instances for each instance when auth. is completed, hence 272326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * must check if it has a valid connection before creating a session. 273326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Returns true at success. */ 274326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public boolean startObexServerSession(BluetoothMnsObexClient mnsClient) throws IOException, RemoteException { 275326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, "Map Service startObexServerSession masid = " + mMasInstanceId); 276326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 277326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mConnSocket != null) { 278326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mServerSession != null) { 279326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // Already connected, just return true 280326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return true; 281326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 282326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mMnsClient = mnsClient; 283326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde BluetoothMapObexServer mapServer; 284326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mObserver = new BluetoothMapContentObserver(mContext, 285326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mMnsClient, 286326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde this, 287326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAccount, 288326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mEnableSmsMms); 289326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mObserver.init(); 290326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mapServer = new BluetoothMapObexServer(mServiceHandler, 291326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mContext, 292326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mObserver, 293326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mMasInstanceId, 294326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAccount, 295326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mEnableSmsMms); 296326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // setup RFCOMM transport 297326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde BluetoothMapRfcommTransport transport = new BluetoothMapRfcommTransport(mConnSocket); 298326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mServerSession = new ServerSession(transport, mapServer, null); 299326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, " ServerSession started."); 300326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 301326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return true; 302326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 303326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, " No connection for this instance"); 304326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return false; 305326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 306326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 307326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public boolean handleSmsSendIntent(Context context, Intent intent){ 308326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mObserver != null) { 309326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return mObserver.handleSmsSendIntent(context, intent); 310326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 311326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return false; 312326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 313326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 314326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 315326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Check if this instance is started. 316326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * @return true if started 317326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 318326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public boolean isStarted() { 319326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde return (mConnSocket != null); 320326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 321326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 322326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public void shutdown() { 323326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, "MAP Service shutdown"); 324326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 325326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mServerSession != null) { 326326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mServerSession.close(); 327326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mServerSession = null; 328326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 329326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mObserver != null) { 330326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mObserver.deinit(); 331326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mObserver = null; 332326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 333326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mInterrupted = true; 334326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if(mAcceptThread != null) { 335326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAcceptThread.shutdown(); 336326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 337326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAcceptThread.join(); 338326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (InterruptedException e) {/* Not much we can do about this*/} 339326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mAcceptThread = null; 340326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 341326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 342326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde closeConnectionSocket(); 343326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 344326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 345326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde /** 346326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Stop a running server session or cleanup, and start a new 347326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * RFComm socket listener thread. 348326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde */ 349326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde public void restartObexServerSession() { 350326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (D) Log.d(TAG, "MAP Service stopObexServerSession"); 351326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 352326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde shutdown(); 353326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 354326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // Last obex transaction is finished, we start to listen for incoming 355326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // connection again - 356326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde startRfcommSocketListener(); 357326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 358326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 359326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 360326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private final synchronized void closeServerSocket() { 361326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // exit SocketAcceptThread early 362326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mServerSocket != null) { 363326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 364326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde // this will cause mServerSocket.accept() return early with IOException 365326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mServerSocket.close(); 366326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException ex) { 367326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.e(TAG, "Close Server Socket error: " + ex); 368326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 369326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mServerSocket = null; 370326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 371326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 372326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 373326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 374326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde private final synchronized void closeConnectionSocket() { 375326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde if (mConnSocket != null) { 376326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde try { 377326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mConnSocket.close(); 378326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } catch (IOException e) { 379326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde Log.e(TAG, "Close Connection Socket error: " + e.toString()); 380326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } finally { 381326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde mConnSocket = null; 382326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 383326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 384326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde } 385326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde 386326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde} 387