1fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie/*
2326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde* Copyright (C) 2014 Samsung System LSI
3fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* Licensed under the Apache License, Version 2.0 (the "License");
4fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* you may not use this file except in compliance with the License.
5fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* You may obtain a copy of the License at
6fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie*
7fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie*      http://www.apache.org/licenses/LICENSE-2.0
8fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie*
9fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* Unless required by applicable law or agreed to in writing, software
10fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* distributed under the License is distributed on an "AS IS" BASIS,
11fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* See the License for the specific language governing permissions and
13fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* limitations under the License.
14fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie*/
15fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xiepackage com.android.bluetooth.map;
16fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
17fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport android.bluetooth.BluetoothDevice;
18fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport android.bluetooth.BluetoothSocket;
19bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport android.bluetooth.SdpMnsRecord;
20fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport android.os.Handler;
2170bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xuimport android.os.HandlerThread;
22fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport android.os.Looper;
23fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport android.os.Message;
24fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport android.os.ParcelUuid;
25fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport android.util.Log;
26326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport android.util.SparseBooleanArray;
27fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
28bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport com.android.bluetooth.BluetoothObexTransport;
29bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
30fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.io.IOException;
31fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.io.OutputStream;
32fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
33fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport javax.obex.ClientOperation;
34fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport javax.obex.ClientSession;
35fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport javax.obex.HeaderSet;
36fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport javax.obex.ObexTransport;
37fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport javax.obex.ResponseCodes;
38fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
39fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie/**
40fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * The Message Notification Service class runs its own message handler thread,
41fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * to avoid executing long operations on the MAP service Thread.
42fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * This handler context is passed to the content observers,
43fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * hence all call-backs (and thereby transmission of data) is executed
44fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie * from this thread.
45fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */
4670bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xupublic class BluetoothMnsObexClient {
47fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
48fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    private static final String TAG = "BluetoothMnsObexClient";
49326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private static final boolean D = BluetoothMapService.DEBUG;
50326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private static final boolean V = BluetoothMapService.VERBOSE;
51fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
52fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    private ObexTransport mTransport;
5370bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu    public Handler mHandler = null;
54fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    private volatile boolean mWaitingForRemote;
55fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    private static final String TYPE_EVENT = "x-bt/MAP-event-report";
56fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    private ClientSession mClientSession;
57fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    private boolean mConnected = false;
58fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    BluetoothDevice mRemoteDevice;
59326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private SparseBooleanArray mRegisteredMasIds = new SparseBooleanArray(1);
60326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
61326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private HeaderSet mHsConnect = null;
62c09b531ba47eee740485b0c6022981fc38ef1587Zhihai Xu    private Handler mCallback = null;
63e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    private SdpMnsRecord mMnsRecord;
64fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    // Used by the MAS to forward notification registrations
65fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public static final int MSG_MNS_NOTIFICATION_REGISTRATION = 1;
66326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    public static final int MSG_MNS_SEND_EVENT = 2;
67e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    public static final int MSG_MNS_SDP_SEARCH_REGISTRATION = 3;
6870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz
69e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    //Copy SdpManager.SDP_INTENT_DELAY - The timeout to wait for reply from native.
70e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    private final int MNS_SDP_SEARCH_DELAY = 6000;
71e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    public MnsSdpSearchInfo mMnsLstRegRqst = null;
72e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    private static final int MNS_NOTIFICATION_DELAY = 10;
73326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    public static final ParcelUuid BLUETOOTH_UUID_OBEX_MNS =
74fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
75fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
76fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
77bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde    public BluetoothMnsObexClient(BluetoothDevice remoteDevice,
78bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            SdpMnsRecord mnsRecord, Handler callback) {
79fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        if (remoteDevice == null) {
80fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            throw new NullPointerException("Obex transport is null");
81fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
82326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        mRemoteDevice = remoteDevice;
8370bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu        HandlerThread thread = new HandlerThread("BluetoothMnsObexClient");
8470bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu        thread.start();
85326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        /* This will block until the looper have started, hence it will be safe to use it,
86326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde           when the constructor completes */
8770bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu        Looper looper = thread.getLooper();
8870bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu        mHandler = new MnsObexClientHandler(looper);
89c09b531ba47eee740485b0c6022981fc38ef1587Zhihai Xu        mCallback = callback;
90bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mMnsRecord = mnsRecord;
91fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
92fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
9370bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu    public Handler getMessageHandler() {
94fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        return mHandler;
95fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
96fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
97e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    class MnsSdpSearchInfo {
98e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        private boolean isSearchInProgress;
99e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        int lastMasId;
100e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        int lastNotificationStatus;
101e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
102e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        MnsSdpSearchInfo (boolean isSearchON, int masId, int notification) {
103e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            isSearchInProgress = isSearchON;
104e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            lastMasId = masId;
105e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            lastNotificationStatus = notification;
106e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        }
107e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
108e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        public boolean isSearchInProgress() {
109e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            return isSearchInProgress;
110e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        }
111e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
112e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        public void setIsSearchInProgress(boolean isSearchON) {
113e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            isSearchInProgress = isSearchON;
114e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        }
115e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    }
116e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
11770bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu    private final class MnsObexClientHandler extends Handler {
11870bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu        private MnsObexClientHandler(Looper looper) {
11970bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu            super(looper);
12070bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu        }
121fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
12270bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu        @Override
12370bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu        public void handleMessage(Message msg) {
12470bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu            switch (msg.what) {
12570bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu            case MSG_MNS_NOTIFICATION_REGISTRATION:
126e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                if (V) Log.v(TAG, "Reg  masId:  " + msg.arg1 + " notfStatus: " + msg.arg2);
127e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                if (isValidMnsRecord()) {
128e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    handleRegistration(msg.arg1 /*masId*/, msg.arg2 /*status*/);
129e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                } else {
130e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    //Should not happen
131e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    if (D) Log.d(TAG, "MNS SDP info not available yet - Cannot Connect.");
132e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                }
13370bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu                break;
134326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            case MSG_MNS_SEND_EVENT:
135326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                sendEventHandler((byte[])msg.obj/*byte[]*/, msg.arg1 /*masId*/);
136326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                break;
137e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            case MSG_MNS_SDP_SEARCH_REGISTRATION:
138e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                //Initiate SDP Search
139e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                notifyMnsSdpSearch();
140e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                //Save the mns search info
141e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                mMnsLstRegRqst = new MnsSdpSearchInfo(true, msg.arg1, msg.arg2);
142e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                //Handle notification registration.
143e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                Message msgReg =
144e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                        mHandler.obtainMessage(MSG_MNS_NOTIFICATION_REGISTRATION,
145e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                                msg.arg1, msg.arg2);
146e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                if (V) Log.v(TAG, "SearchReg  masId:  " + msg.arg1 + " notfStatus: " + msg.arg2);
147e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                mHandler.sendMessageDelayed(msgReg, MNS_SDP_SEARCH_DELAY);
148e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                break;
14970bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu            default:
15070bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu                break;
151fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
15270bfe3280ce158c39dbb25fe18386f0d10b490d3Zhihai Xu        }
153fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
154fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
155fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public boolean isConnected() {
156fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        return mConnected;
157fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
158fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
159824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu    /**
160824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu     * Disconnect the connection to MNS server.
161824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu     * Call this when the MAS client requests a de-registration on events.
162824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu     */
1630e7e149687b0b5e340991b20c9d8e5232e8d3e39Hemant Gupta    public synchronized void disconnect() {
164fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        try {
165fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            if (mClientSession != null) {
166fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                mClientSession.disconnect(null);
167fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                if (D) Log.d(TAG, "OBEX session disconnected");
168fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
169fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } catch (IOException e) {
170fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            Log.w(TAG, "OBEX session disconnect error " + e.getMessage());
171fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
172fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        try {
173fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            if (mClientSession != null) {
174fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                if (D) Log.d(TAG, "OBEX session close mClientSession");
175fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                mClientSession.close();
17670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz                mClientSession = null;
177fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                if (D) Log.d(TAG, "OBEX session closed");
178fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
179fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } catch (IOException e) {
180fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            Log.w(TAG, "OBEX session close error:" + e.getMessage());
181fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
182fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        if (mTransport != null) {
183fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            try {
184fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                if (D) Log.d(TAG, "Close Obex Transport");
185fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                mTransport.close();
18670be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz                mTransport = null;
18770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz                mConnected = false;
188fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                if (D) Log.d(TAG, "Obex Transport Closed");
189fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            } catch (IOException e) {
190fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                Log.e(TAG, "mTransport.close error: " + e.getMessage());
191fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
192fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
193824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu    }
194824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu
195824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu    /**
196824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu     * Shutdown the MNS.
197824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu     */
198189cc4ca1c36018977e7b9ad62b07ddbefc7f2baHemant Gupta    public synchronized void shutdown() {
199824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu        /* should shutdown handler thread first to make sure
200326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde         * handleRegistration won't be called when disconnect
201824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu         */
202824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu        if (mHandler != null) {
203824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu            // Shut down the thread
204824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu            mHandler.removeCallbacksAndMessages(null);
205824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu            Looper looper = mHandler.getLooper();
206824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu            if (looper != null) {
207824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu                looper.quit();
208824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu            }
209824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu            mHandler = null;
210824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu        }
211824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu
212824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu        /* Disconnect if connected */
213824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu        disconnect();
214824929471ee80476e6d6774eedac9f30c5623eb2Zhihai Xu
215326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        mRegisteredMasIds.clear();
216fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
217fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
218326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    /**
219326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * We store a list of registered MasIds only to control connect/disconnect
220326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * @param masId
221326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * @param notificationStatus
222326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     */
223189cc4ca1c36018977e7b9ad62b07ddbefc7f2baHemant Gupta    public synchronized void handleRegistration(int masId, int notificationStatus){
224326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        if(D) Log.d(TAG, "handleRegistration( " + masId + ", " + notificationStatus + ")");
225e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        boolean sendObserverRegistration = true;
226e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        if (notificationStatus == BluetoothMapAppParams.NOTIFICATION_STATUS_NO) {
227326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            mRegisteredMasIds.delete(masId);
228e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            if (mMnsLstRegRqst != null &&  mMnsLstRegRqst.lastMasId == masId) {
229e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                //Clear last saved MNSSdpSearchInfo , if Disconnect requested for same MasId.
230e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                mMnsLstRegRqst = null;
231e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            }
232e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        } else if (notificationStatus == BluetoothMapAppParams.NOTIFICATION_STATUS_YES) {
233fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            /* Connect if we do not have a connection, and start the content observers providing
234fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie             * this thread as Handler.
235fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie             */
236e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            if (isConnected() == false) {
237326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                if(D) Log.d(TAG, "handleRegistration: connect");
238326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                connect();
239fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
240e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            sendObserverRegistration = isConnected();
241326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            mRegisteredMasIds.put(masId, true); // We don't use the value for anything
242e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
243e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            // Clear last saved MNSSdpSearchInfo after connect is processed.
244e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            mMnsLstRegRqst = null;
245326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        }
246e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
247e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        if (mRegisteredMasIds.size() == 0) {
248326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            // No more registrations - disconnect
249326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            if(D) Log.d(TAG, "handleRegistration: disconnect");
250326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            disconnect();
251fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
252e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
253e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        //Register ContentObserver After connect/disconnect MNS channel.
254e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        if (V) Log.v(TAG, "Send  registerObserver: " + sendObserverRegistration);
255e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        if (mCallback != null && sendObserverRegistration) {
256e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            Message msg = Message.obtain(mCallback);
257e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            msg.what = BluetoothMapService.MSG_OBSERVER_REGISTRATION;
258e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            msg.arg1 = masId;
259e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            msg.arg2 = notificationStatus;
260e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            msg.sendToTarget();
261e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        }
262e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    }
263e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
264e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    public boolean isValidMnsRecord() {
265e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        return (mMnsRecord != null);
266e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    }
267e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
268e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    public void setMnsRecord(SdpMnsRecord mnsRecord) {
269e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        if (V) Log.v(TAG, "setMNSRecord");
270e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        if (isValidMnsRecord()) {
271e6564029f132077c8a4877431a95899db201e506Ashwini Munigala           Log.w(TAG,"MNS Record already available. Still update.");
272e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        }
273e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        mMnsRecord = mnsRecord;
274e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        if (mMnsLstRegRqst != null) {
275e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            //SDP Search completed.
276e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            mMnsLstRegRqst.setIsSearchInProgress(false);
277e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            if (mHandler.hasMessages(MSG_MNS_NOTIFICATION_REGISTRATION)) {
278e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                mHandler.removeMessages(MSG_MNS_NOTIFICATION_REGISTRATION);
279e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                //Search Result obtained within MNS_SDP_SEARCH_DELAY timeout
280e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                if (!isValidMnsRecord()) {
281e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    // SDP info still not available for last trial.
282e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    // Clear saved info.
283e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    mMnsLstRegRqst = null;
284e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                } else {
285e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    if (V) Log.v(TAG, "Handle registration for last saved request");
286e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    Message msgReg =
287e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                            mHandler.obtainMessage(MSG_MNS_NOTIFICATION_REGISTRATION);
288e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    msgReg.arg1 = mMnsLstRegRqst.lastMasId;
289e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    msgReg.arg2 = mMnsLstRegRqst.lastNotificationStatus;
290e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    if (V) Log.v(TAG, "SearchReg  masId:  " + msgReg.arg1
291e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                        + " notfStatus: " + msgReg.arg2);
292e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    //Handle notification registration.
293e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                    mHandler.sendMessageDelayed(msgReg, MNS_NOTIFICATION_DELAY);
294e6564029f132077c8a4877431a95899db201e506Ashwini Munigala                }
295e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            }
296e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        } else {
297e6564029f132077c8a4877431a95899db201e506Ashwini Munigala           if (V) Log.v(TAG, "No last saved MNSSDPInfo to handle");
298e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        }
299fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
300fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
301fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public void connect() {
302326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
303326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        mConnected = true;
304fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
305fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        BluetoothSocket btSocket = null;
306fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        try {
307bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            // TODO: Do SDP record search again?
308e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            if (isValidMnsRecord() && mMnsRecord.getL2capPsm() > 0) {
309bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                // Do L2CAP connect
310bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                btSocket = mRemoteDevice.createL2capSocket(mMnsRecord.getL2capPsm());
311bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
312e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            } else if (isValidMnsRecord() && mMnsRecord.getRfcommChannelNumber() > 0) {
313bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                // Do Rfcomm connect
314bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                btSocket = mRemoteDevice.createRfcommSocket(mMnsRecord.getRfcommChannelNumber());
315bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            } else {
316bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                // This should not happen...
317bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                Log.e(TAG, "Invalid SDP content - attempt a connect to UUID...");
318bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                // TODO: Why insecure? - is it because the link is already encrypted?
319bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde              btSocket = mRemoteDevice.createInsecureRfcommSocketToServiceRecord(
320bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde                      BLUETOOTH_UUID_OBEX_MNS.getUuid());
321bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            }
322fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            btSocket.connect();
323fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } catch (IOException e) {
324fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            Log.e(TAG, "BtSocket Connect error " + e.getMessage(), e);
325fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            // TODO: do we need to report error somewhere?
326326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            mConnected = false;
327fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            return;
328fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
329fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
330bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        mTransport = new BluetoothObexTransport(btSocket);
331fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
332fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        try {
333fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            mClientSession = new ClientSession(mTransport);
334fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } catch (IOException e1) {
335fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            Log.e(TAG, "OBEX session create error " + e1.getMessage());
336326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            mConnected = false;
337fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
338fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        if (mConnected && mClientSession != null) {
339326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            boolean connected = false;
340fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            HeaderSet hs = new HeaderSet();
341fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            // bb582b41-420c-11db-b0de-0800200c9a66
342fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            byte[] mnsTarget = { (byte) 0xbb, (byte) 0x58, (byte) 0x2b, (byte) 0x41,
343fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                                 (byte) 0x42, (byte) 0x0c, (byte) 0x11, (byte) 0xdb,
344fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                                 (byte) 0xb0, (byte) 0xde, (byte) 0x08, (byte) 0x00,
345fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                                 (byte) 0x20, (byte) 0x0c, (byte) 0x9a, (byte) 0x66 };
346fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            hs.setHeader(HeaderSet.TARGET, mnsTarget);
347fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
348fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            synchronized (this) {
349fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                mWaitingForRemote = true;
350fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
351fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            try {
352326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                mHsConnect = mClientSession.connect(hs);
353fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                if (D) Log.d(TAG, "OBEX session created");
354326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                connected = true;
355fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            } catch (IOException e) {
356fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                Log.e(TAG, "OBEX session connect error " + e.getMessage());
357fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
358326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            mConnected = connected;
359fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
3605a60e47497f21f64e6d79420dc4c56c1907df22akschulz        synchronized (this) {
361fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                mWaitingForRemote = false;
362fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
363fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
364fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
365326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    /**
366326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * Call this method to queue an event report to be send to the MNS server.
367326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * @param eventBytes the encoded event data.
368326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * @param masInstanceId the MasId of the instance sending the event.
369326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     */
370326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    public void sendEvent(byte[] eventBytes, int masInstanceId) {
371326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        // We need to check for null, to handle shutdown.
372326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        if(mHandler != null) {
373326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            Message msg = mHandler.obtainMessage(MSG_MNS_SEND_EVENT, masInstanceId, 0, eventBytes);
374326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            if(msg != null) {
375326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                msg.sendToTarget();
376326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            }
377326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        }
378326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        notifyUpdateWakeLock();
379326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
380326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
381e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    private void notifyMnsSdpSearch() {
382e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        if (mCallback != null) {
383e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            Message msg = Message.obtain(mCallback);
384e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            msg.what = BluetoothMapService.MSG_MNS_SDP_SEARCH;
385e6564029f132077c8a4877431a95899db201e506Ashwini Munigala            msg.sendToTarget();
386e6564029f132077c8a4877431a95899db201e506Ashwini Munigala        }
387e6564029f132077c8a4877431a95899db201e506Ashwini Munigala    }
388e6564029f132077c8a4877431a95899db201e506Ashwini Munigala
389326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private int sendEventHandler(byte[] eventBytes, int masInstanceId) {
390fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
391fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        boolean error = false;
392fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        int responseCode = -1;
393fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        HeaderSet request;
394fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        int maxChunkSize, bytesToWrite, bytesWritten = 0;
3959679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu        ClientSession clientSession = mClientSession;
3969679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu
3979679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu        if ((!mConnected) || (clientSession == null)) {
3989679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu            Log.w(TAG, "sendEvent after disconnect:" + mConnected);
3999679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu            return responseCode;
4009679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu        }
4019679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu
402fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        request = new HeaderSet();
403fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        BluetoothMapAppParams appParams = new BluetoothMapAppParams();
404fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        appParams.setMasInstanceId(masInstanceId);
405fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
406fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        ClientOperation putOperation = null;
407fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        OutputStream outputStream = null;
408fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
409fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        try {
410fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            request.setHeader(HeaderSet.TYPE, TYPE_EVENT);
411fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            request.setHeader(HeaderSet.APPLICATION_PARAMETER, appParams.EncodeParams());
412fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
413326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            if (mHsConnect.mConnectionID != null) {
4149679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu                request.mConnectionID = new byte[4];
415326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                System.arraycopy(mHsConnect.mConnectionID, 0, request.mConnectionID, 0, 4);
4169679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu            } else {
4179679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu                Log.w(TAG, "sendEvent: no connection ID");
4189679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu            }
419fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
420fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            synchronized (this) {
421fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                mWaitingForRemote = true;
422fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
423fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            // Send the header first and then the body
424fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            try {
425fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                if (V) Log.v(TAG, "Send headerset Event ");
4269679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu                putOperation = (ClientOperation)clientSession.put(request);
427fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                // TODO - Should this be kept or Removed
428fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
429fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            } catch (IOException e) {
430fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                Log.e(TAG, "Error when put HeaderSet " + e.getMessage());
431fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                error = true;
432fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
433fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            synchronized (this) {
434fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                mWaitingForRemote = false;
435fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
436fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            if (!error) {
437fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                try {
438fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    if (V) Log.v(TAG, "Send headerset Event ");
439fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    outputStream = putOperation.openOutputStream();
440fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                } catch (IOException e) {
441fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    Log.e(TAG, "Error when opening OutputStream " + e.getMessage());
442fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    error = true;
443fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                }
444fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
445fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
446fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            if (!error) {
447fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
448fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                maxChunkSize = putOperation.getMaxPacketSize();
449fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
450fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                while (bytesWritten < eventBytes.length) {
451fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    bytesToWrite = Math.min(maxChunkSize, eventBytes.length - bytesWritten);
452fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    outputStream.write(eventBytes, bytesWritten, bytesToWrite);
453fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    bytesWritten += bytesToWrite;
454fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                }
455fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
456fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                if (bytesWritten == eventBytes.length) {
457fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    Log.i(TAG, "SendEvent finished send length" + eventBytes.length);
458fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                } else {
459fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    error = true;
460fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    putOperation.abort();
461fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    Log.i(TAG, "SendEvent interrupted");
462fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                }
463fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
464fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } catch (IOException e) {
465fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            handleSendException(e.toString());
466fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            error = true;
467fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } catch (IndexOutOfBoundsException e) {
468fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            handleSendException(e.toString());
469fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            error = true;
470fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } finally {
471fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            try {
4729679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu                if (outputStream != null) {
4739679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu                    outputStream.close();
4749679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu                }
4759679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu            } catch (IOException e) {
4769679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu                Log.e(TAG, "Error when closing stream after send " + e.getMessage());
4779679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu            }
4789679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu            try {
4799679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu                if ((!error) && (putOperation != null)) {
480fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    responseCode = putOperation.getResponseCode();
481fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    if (responseCode != -1) {
482fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                        if (V) Log.v(TAG, "Put response code " + responseCode);
483fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                        if (responseCode != ResponseCodes.OBEX_HTTP_OK) {
484fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                            Log.i(TAG, "Response error code is " + responseCode);
485fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                        }
486fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                    }
487fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                }
488fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                if (putOperation != null) {
4899679a425747e95082e169b3bd3673ed6b5a27590Zhihai Xu                    putOperation.close();
490fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                }
491fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            } catch (IOException e) {
492fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie                Log.e(TAG, "Error when closing stream after send " + e.getMessage());
493fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
494fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
495fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
496fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        return responseCode;
497fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
498fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
499fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    private void handleSendException(String exception) {
500fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        Log.e(TAG, "Error when sending event: " + exception);
501fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
502c09b531ba47eee740485b0c6022981fc38ef1587Zhihai Xu
503c09b531ba47eee740485b0c6022981fc38ef1587Zhihai Xu    private void notifyUpdateWakeLock() {
504326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        if(mCallback != null) {
505326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            Message msg = Message.obtain(mCallback);
506326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            msg.what = BluetoothMapService.MSG_ACQUIRE_WAKE_LOCK;
507326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            msg.sendToTarget();
508326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        }
509c09b531ba47eee740485b0c6022981fc38ef1587Zhihai Xu    }
510fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie}
511