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