1 /*
2  * Copyright (c) 2008-2009, Motorola, Inc.
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * - Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * - Neither the name of the Motorola, Inc. nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.android.bluetooth.opp;
34 
35 import com.android.bluetooth.R;
36 
37 import android.app.Activity;
38 import android.content.ContentValues;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.database.Cursor;
42 import android.net.Uri;
43 import android.os.Bundle;
44 import android.os.Handler;
45 import android.os.Message;
46 import android.util.Log;
47 import android.widget.Button;
48 import android.widget.EditText;
49 import android.view.View;
50 import android.view.View.OnClickListener;
51 
52 import java.io.DataInputStream;
53 import java.io.DataOutputStream;
54 import java.io.File;
55 import java.io.FileOutputStream;
56 import java.io.IOException;
57 import java.io.InputStream;
58 import java.io.OutputStream;
59 import java.net.ServerSocket;
60 import java.net.Socket;
61 import java.net.SocketException;
62 
63 import javax.obex.Authenticator;
64 import javax.obex.HeaderSet;
65 import javax.obex.ObexTransport;
66 import javax.obex.Operation;
67 import javax.obex.ResponseCodes;
68 import javax.obex.ServerRequestHandler;
69 import javax.obex.ServerSession;
70 
71 public class TestActivity extends Activity {
72 
73     public String currentInsert;
74 
75     public int mCurrentByte = 0;
76 
77     EditText mUpdateView;
78 
79     EditText mAckView;
80 
81     EditText mDeleteView;
82 
83     EditText mInsertView;
84 
85     EditText mAddressView;
86 
87     EditText mMediaView;
88 
89     TestTcpServer server;
90 
91     /** Called when the activity is first created. */
92     @Override
onCreate(Bundle savedInstanceState)93     public void onCreate(Bundle savedInstanceState) {
94         super.onCreate(savedInstanceState);
95 
96         Intent intent = getIntent();
97 
98         String action = intent.getAction();
99 
100         Context c = getBaseContext();
101 
102         if (Intent.ACTION_SEND.equals(action)) {
103             /*
104              * Other application is trying to share a file via Bluetooth,
105              * probably Pictures, or vCard. The Intent should contain an
106              * EXTRA_STREAM with the data to attach.
107              */
108 
109             String type = intent.getType();
110             Uri stream = (Uri)intent.getParcelableExtra(Intent.EXTRA_STREAM);
111 
112             if (stream != null && type != null) {
113                 /*
114                  * if (MimeUtility.mimeTypeMatches(type,
115                  * Email.ACCEPTABLE_ATTACHMENT_SEND_TYPES)) {
116                  * addAttachment(stream);
117                  */
118                 Log.v(Constants.TAG, " Get share intent with Uri " + stream + " mimetype is "
119                         + type);
120                 // Log.v(Constants.TAG, " trying Uri function " +
121                 // stream.getAuthority() + " " + Uri.parse(stream));
122                 Cursor cursor = c.getContentResolver().query(stream, null, null, null, null);
123                 cursor.close();
124 
125             }
126             /* start insert a record */
127             /*
128              * ContentValues values = new ContentValues();
129              * values.put(BluetoothShare.URI, stream.toString());
130              * values.put(BluetoothShare.DESTINATION, "FF:FF:FF:00:00:00");
131              * values.put(BluetoothShare.DIRECTION,
132              * BluetoothShare.DIRECTION_OUTBOUND); final Uri contentUri =
133              * getContentResolver().insert(BluetoothShare.CONTENT_URI, values);
134              * Log.v(Constants.TAG, "insert contentUri: " + contentUri);
135              */
136         }
137         /*
138          * Context c = getBaseContext(); c.startService(new Intent(c,
139          * BluetoothOppService.class));
140          */
141 
142         setContentView(R.layout.testactivity_main);
143 
144         Button mInsertRecord = (Button)findViewById(R.id.insert_record);
145         Button mDeleteRecord = (Button)findViewById(R.id.delete_record);
146         Button mUpdateRecord = (Button)findViewById(R.id.update_record);
147 
148         Button mAckRecord = (Button)findViewById(R.id.ack_record);
149 
150         Button mDeleteAllRecord = (Button)findViewById(R.id.deleteAll_record);
151         mUpdateView = (EditText)findViewById(R.id.update_text);
152         mAckView = (EditText)findViewById(R.id.ack_text);
153         mDeleteView = (EditText)findViewById(R.id.delete_text);
154         mInsertView = (EditText)findViewById(R.id.insert_text);
155 
156         mAddressView = (EditText)findViewById(R.id.address_text);
157         mMediaView = (EditText)findViewById(R.id.media_text);
158 
159         mInsertRecord.setOnClickListener(insertRecordListener);
160         mDeleteRecord.setOnClickListener(deleteRecordListener);
161         mUpdateRecord.setOnClickListener(updateRecordListener);
162         mAckRecord.setOnClickListener(ackRecordListener);
163         mDeleteAllRecord.setOnClickListener(deleteAllRecordListener);
164 
165         Button mStartTcpServer = (Button)findViewById(R.id.start_server);
166         mStartTcpServer.setOnClickListener(startTcpServerListener);
167 
168         Button mNotifyTcpServer = (Button)findViewById(R.id.notify_server);
169         mNotifyTcpServer.setOnClickListener(notifyTcpServerListener);
170         /* parse insert result Uri */
171         /*
172          * String id = contentUri.getPathSegments().get(1); Log.v(Constants.TAG,
173          * "insert record id is " + id); Uri contentUri1 =
174          * Uri.parse(BluetoothShare.CONTENT_URI + "/" + id);
175          */
176         /* update a single column of a record */
177         /*
178          * ContentValues updateValues = new ContentValues();
179          * updateValues.put(BluetoothShare.TOTAL_BYTES, 120000);
180          * getContentResolver().update(contentUri1,updateValues,null,null);
181          */
182         /* query a single column of a record */
183         /*
184          * Cursor queryC = getContentResolver().query(contentUri1, null, null,
185          * null, null); if (queryC != null) { if (queryC.moveToFirst()) { int
186          * currentByteColumn =
187          * queryC.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES); int
188          * currentByte = queryC.getInt(currentByteColumn);
189          */
190         /* update a column of a record */
191         /*
192          * for(int i =0;i<100;i++){ currentByte ++;
193          * updateValues.put(BluetoothShare.CURRENT_BYTES, currentByte);
194          * getContentResolver().update(contentUri1,updateValues,null,null); } }
195          * }
196          */
197         /* query whole data base */
198         /*
199          * Cursor c = managedQuery(contentUri1, new String [] {"_id",
200          * BluetoothShare.URI, BluetoothShare.STATUS,
201          * BluetoothShare.TOTAL_BYTES, BluetoothShare.CURRENT_BYTES,
202          * BluetoothShare._DATA, BluetoothShare.DIRECTION,
203          * BluetoothShare.MIMETYPE, BluetoothShare.DESTINATION,
204          * BluetoothShare.VISIBILITY, BluetoothShare.USER_CONFIRMATION,
205          * BluetoothShare.TIMESTAMP}, null, null, null); Log.v(Constants.TAG,
206          * "query " + contentUri1 +" get " + c.getCount()+" records");
207          */
208         /* delete a record */
209         /*
210          * Uri contentUri2 = Uri.parse(BluetoothShare.CONTENT_URI + "/" + 1);
211          * getContentResolver().delete(contentUri2, null, null);
212          */
213 
214     }
215 
216     public OnClickListener insertRecordListener = new OnClickListener() {
217         public void onClick(View view) {
218 
219             String address = null;
220             if (mAddressView.getText().length() != 0) {
221                 address = mAddressView.getText().toString();
222                 Log.v(Constants.TAG, "Send to address  " + address);
223             }
224             if (address == null) {
225                 address = "00:17:83:58:5D:CC";
226             }
227 
228             Integer media = null;
229             if (mMediaView.getText().length() != 0) {
230                 media = Integer.parseInt(mMediaView.getText().toString().trim());
231                 Log.v(Constants.TAG, "Send media no.  " + media);
232             }
233             if (media == null) {
234                 media = 1;
235             }
236             ContentValues values = new ContentValues();
237             values.put(BluetoothShare.URI, "content://media/external/images/media/" + media);
238             // values.put(BluetoothShare.DESTINATION, "FF:FF:FF:00:00:00");
239             // baibai Q9 test
240             // values.put(BluetoothShare.DESTINATION, "12:34:56:78:9A:BC");
241             // java's nokia
242             // values.put(BluetoothShare.DESTINATION, "00:1B:33:F0:58:FB");
243             // Assis phone
244             // values.put(BluetoothShare.DESTINATION, "00:17:E5:5D:74:F3");
245             // Jackson E6
246             // values.put(BluetoothShare.DESTINATION, "00:1A:1B:7F:1E:F0");
247             // Baibai V950
248             // values.put(BluetoothShare.DESTINATION, "00:17:83:58:5D:CC");
249             // Baibai NSC1173
250             // values.put(BluetoothShare.DESTINATION, "00:16:41:49:5B:F3");
251 
252             values.put(BluetoothShare.DESTINATION, address);
253 
254             values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
255 
256             Long ts = System.currentTimeMillis();
257             values.put(BluetoothShare.TIMESTAMP, ts);
258 
259             Integer records = null;
260             if (mInsertView.getText().length() != 0) {
261                 records = Integer.parseInt(mInsertView.getText().toString().trim());
262                 Log.v(Constants.TAG, "parseInt  " + records);
263             }
264             if (records == null) {
265                 records = 1;
266             }
267             for (int i = 0; i < records; i++) {
268                 Uri contentUri = getContentResolver().insert(BluetoothShare.CONTENT_URI, values);
269                 Log.v(Constants.TAG, "insert contentUri: " + contentUri);
270                 currentInsert = contentUri.getPathSegments().get(1);
271                 Log.v(Constants.TAG, "currentInsert = " + currentInsert);
272             }
273 
274         }
275     };
276 
277     public OnClickListener deleteRecordListener = new OnClickListener() {
278         public void onClick(View view) {
279             Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/"
280                     + mDeleteView.getText().toString());
281             getContentResolver().delete(contentUri, null, null);
282         }
283     };
284 
285     public OnClickListener updateRecordListener = new OnClickListener() {
286         public void onClick(View view) {
287             Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/"
288                     + mUpdateView.getText().toString());
289             ContentValues updateValues = new ContentValues();
290             // mCurrentByte ++;
291             // updateValues.put(BluetoothShare.TOTAL_BYTES, "120000");
292             // updateValues.put(BluetoothShare.CURRENT_BYTES, mCurrentByte);
293             // updateValues.put(BluetoothShare.VISIBILITY,
294             // BluetoothShare.VISIBILITY_HIDDEN);
295             updateValues.put(BluetoothShare.USER_CONFIRMATION,
296                     BluetoothShare.USER_CONFIRMATION_CONFIRMED);
297             getContentResolver().update(contentUri, updateValues, null, null);
298         }
299     };
300 
301     public OnClickListener ackRecordListener = new OnClickListener() {
302         public void onClick(View view) {
303             Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/"
304                     + mAckView.getText().toString());
305             ContentValues updateValues = new ContentValues();
306             // mCurrentByte ++;
307             // updateValues.put(BluetoothShare.TOTAL_BYTES, "120000");
308             // updateValues.put(BluetoothShare.CURRENT_BYTES, mCurrentByte);
309             updateValues.put(BluetoothShare.VISIBILITY, BluetoothShare.VISIBILITY_HIDDEN);
310             // updateValues.put(BluetoothShare.USER_CONFIRMATION,
311             // BluetoothShare.USER_CONFIRMATION_CONFIRMED);
312             getContentResolver().update(contentUri, updateValues, null, null);
313         }
314     };
315 
316     public OnClickListener deleteAllRecordListener = new OnClickListener() {
317         public void onClick(View view) {
318             Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "");
319             getContentResolver().delete(contentUri, null, null);
320         }
321     };
322 
323     public OnClickListener startTcpServerListener = new OnClickListener() {
324         public void onClick(View view) {
325             server = new TestTcpServer();
326             Thread server_thread = new Thread(server);
327             server_thread.start();
328 
329         }
330     };
331 
332     public OnClickListener notifyTcpServerListener = new OnClickListener() {
333         public void onClick(View view) {
334             final Thread notifyThread = new Thread() {
335                 public void run() {
336                     synchronized (server) {
337                         server.a = true;
338                         server.notify();
339                     }
340                 }
341 
342             };
343             notifyThread.start();
344         }
345 
346     };
347 }
348 
349 /**
350  * This class listens on OPUSH channel for incoming connection
351  */
352 class TestTcpListener {
353 
354     private static final String TAG = "BtOppRfcommListener";
355 
356     private static final boolean D = Constants.DEBUG;
357 
358     private static final boolean V = Constants.VERBOSE;
359 
360     private volatile boolean mInterrupted;
361 
362     private Thread mSocketAcceptThread;
363 
364     private Handler mCallback;
365 
366     private static final int ACCEPT_WAIT_TIMEOUT = 5000;
367 
368     public static final int DEFAULT_OPP_CHANNEL = 12;
369 
370     public static final int MSG_INCOMING_BTOPP_CONNECTION = 100;
371 
372     private int mBtOppRfcommChannel = -1;
373 
TestTcpListener()374     public TestTcpListener() {
375         this(DEFAULT_OPP_CHANNEL);
376     }
377 
TestTcpListener(int channel)378     public TestTcpListener(int channel) {
379         mBtOppRfcommChannel = channel;
380     }
381 
start(Handler callback)382     public synchronized boolean start(Handler callback) {
383         if (mSocketAcceptThread == null) {
384             mCallback = callback;
385             mSocketAcceptThread = new Thread(TAG) {
386                 ServerSocket mServerSocket;
387 
388                 public void run() {
389                     if (D) Log.d(TAG, "RfcommSocket listen thread starting");
390                     try {
391                         if (V)
392                             Log.v(TAG, "Create server RfcommSocket on channel"
393                                     + mBtOppRfcommChannel);
394                         mServerSocket = new ServerSocket(6500, 1);
395                     } catch (IOException e) {
396                         Log.e(TAG, "Error listing on channel" + mBtOppRfcommChannel);
397                         mInterrupted = true;
398                     }
399                     while (!mInterrupted) {
400                         try {
401                             mServerSocket.setSoTimeout(ACCEPT_WAIT_TIMEOUT);
402                             Socket clientSocket = mServerSocket.accept();
403                             if (clientSocket == null) {
404                                 if (V) Log.v(TAG, "incomming connection time out");
405                             } else {
406                                 if (D) Log.d(TAG, "RfcommSocket connected!");
407                                 Log.d(TAG, "remote addr is "
408                                         + clientSocket.getRemoteSocketAddress());
409                                 TestTcpTransport transport = new TestTcpTransport(clientSocket);
410                                 Message msg = Message.obtain();
411                                 msg.setTarget(mCallback);
412                                 msg.what = MSG_INCOMING_BTOPP_CONNECTION;
413                                 msg.obj = transport;
414                                 msg.sendToTarget();
415                             }
416                         } catch (SocketException e) {
417                             Log.e(TAG, "Error accept connection " + e);
418                         } catch (IOException e) {
419                             Log.e(TAG, "Error accept connection " + e);
420                         }
421 
422                         if (mInterrupted) {
423                             Log.e(TAG, "socketAcceptThread thread was interrupted (2), exiting");
424                         }
425                     }
426                     if (D) Log.d(TAG, "RfcommSocket listen thread finished");
427                 }
428             };
429             mInterrupted = false;
430             mSocketAcceptThread.start();
431 
432         }
433         return true;
434 
435     }
436 
stop()437     public synchronized void stop() {
438         if (mSocketAcceptThread != null) {
439             if (D) Log.d(TAG, "stopping Connect Thread");
440             mInterrupted = true;
441             try {
442                 mSocketAcceptThread.interrupt();
443                 if (V) Log.v(TAG, "waiting for thread to terminate");
444                 mSocketAcceptThread.join();
445                 mSocketAcceptThread = null;
446                 mCallback = null;
447             } catch (InterruptedException e) {
448                 if (V) Log.v(TAG, "Interrupted waiting for Accept Thread to join");
449             }
450         }
451     }
452 
453 }
454 
455 class TestTcpServer extends ServerRequestHandler implements Runnable {
456     private static final String TAG = "ServerRequestHandler";
457 
458     private static final boolean V = Constants.VERBOSE;
459 
460     static final int port = 6500;
461 
462     public boolean a = false;
463 
464     // TextView serverStatus = null;
run()465     public void run() {
466         try {
467             updateStatus("[server:] listen on port " + port);
468             TestTcpSessionNotifier rsn = new TestTcpSessionNotifier(port);
469 
470             updateStatus("[server:] Now waiting for a client to connect");
471             rsn.acceptAndOpen(this);
472             updateStatus("[server:] A client is now connected");
473         } catch (Exception ex) {
474             updateStatus("[server:] Caught the error: " + ex);
475         }
476     }
477 
TestTcpServer()478     public TestTcpServer() {
479         updateStatus("enter construtor of TcpServer");
480     }
481 
onConnect(HeaderSet request, HeaderSet reply)482     public int onConnect(HeaderSet request, HeaderSet reply) {
483 
484         updateStatus("[server:] The client has created an OBEX session");
485         /* sleep for 2000 ms to wait for the batch contains all ShareInfos */
486         synchronized (this) {
487             try {
488                 while (!a) {
489                     wait(500);
490                 }
491             } catch (InterruptedException e) {
492                 if (V) Log.v(TAG, "Interrupted waiting for markBatchFailed");
493             }
494         }
495         updateStatus("[server:] we accpet the seesion");
496         return ResponseCodes.OBEX_HTTP_OK;
497     }
498 
onPut(Operation op)499     public int onPut(Operation op) {
500         FileOutputStream fos = null;
501         try {
502             java.io.InputStream is = op.openInputStream();
503 
504             updateStatus("Got data bytes " + is.available() + " name "
505                     + op.getReceivedHeader().getHeader(HeaderSet.NAME) + " type " + op.getType());
506 
507             File f = new File((String)op.getReceivedHeader().getHeader(HeaderSet.NAME));
508             fos = new FileOutputStream(f);
509             byte b[] = new byte[1000];
510             int len;
511 
512             while (is.available() > 0 && (len = is.read(b)) > 0) {
513                 fos.write(b, 0, len);
514             }
515 
516             fos.close();
517             is.close();
518             updateStatus("[server:] Wrote data to " + f.getAbsolutePath());
519         } catch (Exception e) {
520             if (fos != null) {
521                 try {
522                     fos.close();
523                 } catch (IOException e1) {
524                     e1.printStackTrace();
525                 }
526             }
527             e.printStackTrace();
528         }
529         return ResponseCodes.OBEX_HTTP_OK;
530     }
531 
onDisconnect(HeaderSet req, HeaderSet resp)532     public void onDisconnect(HeaderSet req, HeaderSet resp) {
533         updateStatus("[server:] The client has disconnected the OBEX session");
534     }
535 
updateStatus(String message)536     public void updateStatus(String message) {
537         Log.v(TAG, "\n" + message);
538     }
539 
onAuthenticationFailure(byte[] userName)540     public void onAuthenticationFailure(byte[] userName) {
541     }
542 
onSetPath(HeaderSet request, HeaderSet reply, boolean backup, boolean create)543     public int onSetPath(HeaderSet request, HeaderSet reply, boolean backup, boolean create) {
544 
545         return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
546     }
547 
onDelete(HeaderSet request, HeaderSet reply)548     public int onDelete(HeaderSet request, HeaderSet reply) {
549         return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
550     }
551 
onGet(Operation op)552     public int onGet(Operation op) {
553         return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
554     }
555 
556 }
557 
558 class TestTcpSessionNotifier {
559     /* implements SessionNotifier */
560 
561     ServerSocket server = null;
562 
563     Socket conn = null;
564 
565     private static final String TAG = "TestTcpSessionNotifier";
566 
TestTcpSessionNotifier(int port)567     public TestTcpSessionNotifier(int port) throws IOException {
568         server = new ServerSocket(port);
569     }
570 
acceptAndOpen(ServerRequestHandler handler, Authenticator auth)571     public ServerSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth)
572             throws IOException {
573         try {
574             conn = server.accept();
575 
576         } catch (Exception ex) {
577             Log.v(TAG, "ex");
578         }
579 
580         TestTcpTransport tt = new TestTcpTransport(conn);
581 
582         return new ServerSession((ObexTransport)tt, handler, auth);
583 
584     }
585 
acceptAndOpen(ServerRequestHandler handler)586     public ServerSession acceptAndOpen(ServerRequestHandler handler) throws IOException {
587 
588         return acceptAndOpen(handler, null);
589 
590     }
591 
592 }
593 
594 class TestTcpTransport implements ObexTransport {
595 
596     Socket s = null;
597 
TestTcpTransport(Socket s)598     public TestTcpTransport(Socket s) {
599         super();
600         this.s = s;
601     }
602 
close()603     public void close() throws IOException {
604         s.close();
605     }
606 
openDataInputStream()607     public DataInputStream openDataInputStream() throws IOException {
608         return new DataInputStream(openInputStream());
609     }
610 
openDataOutputStream()611     public DataOutputStream openDataOutputStream() throws IOException {
612         return new DataOutputStream(openOutputStream());
613     }
614 
openInputStream()615     public InputStream openInputStream() throws IOException {
616         return s.getInputStream();
617     }
618 
openOutputStream()619     public OutputStream openOutputStream() throws IOException {
620         return s.getOutputStream();
621     }
622 
connect()623     public void connect() throws IOException {
624         // TODO Auto-generated method stub
625 
626     }
627 
create()628     public void create() throws IOException {
629         // TODO Auto-generated method stub
630 
631     }
632 
disconnect()633     public void disconnect() throws IOException {
634         // TODO Auto-generated method stub
635 
636     }
637 
listen()638     public void listen() throws IOException {
639         // TODO Auto-generated method stub
640 
641     }
642 
isConnected()643     public boolean isConnected() throws IOException {
644         return s.isConnected();
645     }
646 
647 }
648