1package com.android.bluetooth.tests;
2
3import java.io.IOException;
4import java.util.ArrayList;
5import java.util.Arrays;
6import java.util.concurrent.CountDownLatch;
7
8import javax.obex.HeaderSet;
9import javax.obex.Operation;
10import javax.obex.ServerRequestHandler;
11
12import junit.framework.Assert;
13import android.annotation.TargetApi;
14import android.bluetooth.BluetoothServerSocket;
15import android.bluetooth.BluetoothSocket;
16import android.net.LocalServerSocket;
17import android.net.LocalSocket;
18import android.os.Build;
19import android.os.RemoteException;
20import android.test.AndroidTestCase;
21import android.util.Log;
22
23import com.android.bluetooth.BluetoothObexTransport;
24import com.android.bluetooth.tests.TestSequencer.OPTYPE;
25
26@TargetApi(Build.VERSION_CODES.KITKAT)
27public class MapObexLevelTest extends AndroidTestCase implements ITestSequenceConfigurator {
28    protected static String TAG = "MapObexLevelTest";
29    protected static final boolean D = true;
30    protected static final boolean TRACE = false;
31    protected static final boolean DELAY_PASS_30_SEC = true;
32
33    // 128 bit UUID for MAP MAS
34    static final byte[] MAS_TARGET = new byte[] {
35             (byte)0xBB, (byte)0x58, (byte)0x2B, (byte)0x40,
36             (byte)0x42, (byte)0x0C, (byte)0x11, (byte)0xDB,
37             (byte)0xB0, (byte)0xDE, (byte)0x08, (byte)0x00,
38             (byte)0x20, (byte)0x0C, (byte)0x9A, (byte)0x66
39             };
40
41    // 128 bit UUID for MAP MNS
42    static final byte[] MNS_TARGET = new byte[] {
43             (byte)0xBB, (byte)0x58, (byte)0x2B, (byte)0x41,
44             (byte)0x42, (byte)0x0C, (byte)0x11, (byte)0xDB,
45             (byte)0xB0, (byte)0xDE, (byte)0x08, (byte)0x00,
46             (byte)0x20, (byte)0x0C, (byte)0x9A, (byte)0x66
47             };
48
49    /* Message types */
50    static final String TYPE_GET_FOLDER_LISTING              = "x-obex/folder-listing";
51    static final String TYPE_GET_MESSAGE_LISTING             = "x-bt/MAP-msg-listing";
52    static final String TYPE_GET_CONVO_LISTING               = "x-bt/MAP-convo-listing";
53    static final String TYPE_MESSAGE                         = "x-bt/message";
54    static final String TYPE_SET_MESSAGE_STATUS              = "x-bt/messageStatus";
55    static final String TYPE_SET_NOTIFICATION_REGISTRATION   = "x-bt/MAP-NotificationRegistration";
56    static final String TYPE_MESSAGE_UPDATE                  = "x-bt/MAP-messageUpdate";
57    static final String TYPE_GET_MAS_INSTANCE_INFORMATION    = "x-bt/MASInstanceInformation";
58
59    public void testFolder() {
60        testLocalSockets(new buildFolderTestSeq());
61    }
62
63    public void testFolderServer() {
64        testServer(new buildFolderTestSeq());
65    }
66
67    public void testFolderClient() {
68        testClient(new buildFolderTestSeq());
69    }
70
71    protected class buildFolderTestSeq implements ITestSequenceBuilder {
72        @Override
73        public void build(TestSequencer sequencer) {
74            addConnectStep(sequencer);
75
76            MapStepsFolder.addGoToMsgFolderSteps(sequencer);
77
78            // MAP DISCONNECT Step
79            addDisconnectStep(sequencer);
80        }
81    }
82
83
84    public void testConvo() {
85        testLocalSockets(new buildConvoTestSeq());
86    }
87
88    public void testConvoServer() {
89        testServer(new buildConvoTestSeq());
90    }
91
92    public void testConvoClient() {
93        testClient(new buildConvoTestSeq());
94    }
95
96    class buildConvoTestSeq implements ITestSequenceBuilder {
97        @Override
98        public void build(TestSequencer sequencer) {
99            addConnectStep(sequencer);
100
101            MapStepsFolder.addGoToMsgFolderSteps(sequencer);
102
103            MapStepsConvo.addConvoListingSteps(sequencer);
104
105            // MAP DISCONNECT Step
106            addDisconnectStep(sequencer);
107        }
108    }
109
110    /**
111     * Run the test sequence using a local socket on a single device.
112     * Throughput around 4000 kbyte/s - with a larger OBEX package size.
113     *
114     * Downside: Unable to get a BT-snoop file...
115     */
116    protected void testLocalSockets(ITestSequenceBuilder builder) {
117        mContext = this.getContext();
118        MapTestData.init(mContext);
119        Log.i(TAG,"Setting up sockets...");
120
121        try {
122            /* Create and interconnect local pipes for transport */
123            LocalServerSocket serverSock = new LocalServerSocket("com.android.bluetooth.tests.sock");
124            LocalSocket clientSock = new LocalSocket();
125            LocalSocket acceptSock;
126
127            clientSock.connect(serverSock.getLocalSocketAddress());
128
129            acceptSock = serverSock.accept();
130
131            /* Create the OBEX transport objects to wrap the pipes - enable SRM */
132            ObexPipeTransport clientTransport = new ObexPipeTransport(clientSock.getInputStream(),
133                    clientSock.getOutputStream(), true);
134            ObexPipeTransport serverTransport = new ObexPipeTransport(acceptSock.getInputStream(),
135                    acceptSock.getOutputStream(), true);
136
137            TestSequencer sequencer  = new TestSequencer(clientTransport, serverTransport, this);
138
139            builder.build(sequencer);
140
141            //Debug.startMethodTracing("ObexTrace");
142            assertTrue(sequencer.run(mContext));
143            //Debug.stopMethodTracing();
144
145            clientSock.close();
146            acceptSock.close();
147            serverSock.close();
148        } catch (IOException e) {
149            Log.e(TAG, "IOException", e);
150        }
151    }
152
153    /**
154     * Server side of a dual device test using a Bluetooth Socket.
155     * Enables the possibility to get a BT-snoop file.
156     * If you need the btsnoop from the device which completes the test with success
157     * you need to add a delay after the test ends, and fetch the file before this delay
158     * expires. When the test completes, the Bluetooth subsystem will be restarted, causing
159     * a new bt-snoop to overwrite the one used in test.
160     */
161    public void testServer(ITestSequenceBuilder builder) {
162        mContext = this.getContext();
163        MapTestData.init(mContext);
164        Log.i(TAG,"Setting up sockets...");
165
166        try {
167            /* This will turn on BT and create a server socket on which accept can be called. */
168            BluetoothServerSocket serverSocket=ObexTest.createServerSocket(BluetoothSocket.TYPE_L2CAP, true);
169
170            Log.i(TAG, "Waiting for client to connect...");
171            BluetoothSocket socket = serverSocket.accept();
172            Log.i(TAG, "Client connected...");
173
174            BluetoothObexTransport serverTransport = new BluetoothObexTransport(socket);
175
176            TestSequencer sequencer  = new TestSequencer(null, serverTransport, this);
177
178            builder.build(sequencer);
179
180            //Debug.startMethodTracing("ObexTrace");
181            assertTrue(sequencer.run(mContext));
182            //Debug.stopMethodTracing();
183
184            serverSocket.close();
185            socket.close();
186        } catch (IOException e) {
187            Log.e(TAG, "IOException", e);
188        }
189        if(DELAY_PASS_30_SEC) {
190            Log.i(TAG, "\n\n\nTest done - please fetch logs within 30 seconds...\n\n\n");
191            try {
192                Thread.sleep(30000);
193            } catch (InterruptedException e) {}
194        }
195    }
196
197    /**
198     * Server side of a dual device test using a Bluetooth Socket.
199     * Enables the possibility to get a BT-snoop file.
200     * If you need the btsnoop from the device which completes the test with success
201     * you need to add a delay after the test ends, and fetch the file before this delay
202     * expires. When the test completes, the Bluetooth subsystem will be restarted, causing
203     * a new bt-snoop to overwrite the one used in test.
204     */
205    public void testClient(ITestSequenceBuilder builder) {
206        mContext = this.getContext();
207        MapTestData.init(mContext);
208        Log.i(TAG, "Setting up sockets...");
209
210        try {
211            /* This will turn on BT and connect */
212            BluetoothSocket clientSock =
213                    ObexTest.connectClientSocket(BluetoothSocket.TYPE_L2CAP, true, mContext);
214
215            BluetoothObexTransport clientTransport = new BluetoothObexTransport(clientSock);
216
217            TestSequencer sequencer  = new TestSequencer(clientTransport, null, this);
218
219            builder.build(sequencer);
220
221            //Debug.startMethodTracing("ObexTrace");
222            assertTrue(sequencer.run(mContext));
223            //Debug.stopMethodTracing();
224
225            clientSock.close();
226        } catch (IOException e) {
227            Log.e(TAG, "IOException", e);
228        }
229        if(DELAY_PASS_30_SEC) {
230            Log.i(TAG, "\n\n\nTest done - please fetch logs within 30 seconds...\n\n\n");
231            try {
232                Thread.sleep(30000);
233            } catch (InterruptedException e) {}
234        }
235    }
236
237    protected void addConnectStep(TestSequencer sequencer) {
238        SeqStep step;
239
240        // MAP CONNECT Step
241        step = sequencer.addStep(OPTYPE.CONNECT, null);
242        HeaderSet hs = new HeaderSet();
243        hs.setHeader(HeaderSet.TARGET, MAS_TARGET);
244        step.mReqHeaders = hs;
245        step.mValidator = new MapConnectValidator();
246        //step.mServerPreAction = new MapAddSmsMessages(); // could take in parameters
247    }
248
249    protected void addDisconnectStep(TestSequencer sequencer) {
250        sequencer.addStep(OPTYPE.DISCONNECT, ObexTest.getResponsecodevalidator());
251    }
252
253    /* Functions to validate results */
254
255    private class MapConnectValidator implements ISeqStepValidator {
256        @Override
257        public boolean validate(SeqStep step, HeaderSet response, Operation notUsed)
258                throws IOException {
259            Assert.assertNotNull(response);
260            byte[] who = (byte[])response.getHeader(HeaderSet.WHO);
261            Assert.assertNotNull(who);
262            Assert.assertTrue(Arrays.equals(who, MAS_TARGET));
263            Assert.assertNotNull(response.getHeader(HeaderSet.CONNECTION_ID));
264            return true;
265        }
266    }
267
268    /**
269     * This is the function creating the Obex Server to be used in this class.
270     * Here we use a mocked version of the MapObexServer class
271     */
272    @Override
273    public ServerRequestHandler getObexServer(ArrayList<SeqStep> sequence,
274            CountDownLatch stopLatch) {
275        try {
276            return new MapObexTestServer(mContext, sequence, stopLatch);
277        } catch (RemoteException e) {
278            Log.e(TAG, "exception", e);
279            fail("Unable to create MapObexTestServer");
280        }
281        return null;
282    }
283
284
285}
286
287