| /* |
| * Copyright (c) 2008-2009, Motorola, Inc. |
| * |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * - Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * - Neither the name of the Motorola, Inc. nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| package com.android.bluetooth.opp; |
| |
| import com.android.bluetooth.R; |
| |
| import android.app.Activity; |
| import android.content.ContentValues; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.database.Cursor; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.util.Log; |
| import android.widget.Button; |
| import android.widget.EditText; |
| import android.view.View; |
| import android.view.View.OnClickListener; |
| |
| import java.io.DataInputStream; |
| import java.io.DataOutputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.net.SocketException; |
| |
| import javax.obex.Authenticator; |
| import javax.obex.HeaderSet; |
| import javax.obex.ObexTransport; |
| import javax.obex.Operation; |
| import javax.obex.ResponseCodes; |
| import javax.obex.ServerRequestHandler; |
| import javax.obex.ServerSession; |
| |
| public class TestActivity extends Activity { |
| |
| public String currentInsert; |
| |
| public int mCurrentByte = 0; |
| |
| EditText mUpdateView; |
| |
| EditText mAckView; |
| |
| EditText mDeleteView; |
| |
| EditText mInsertView; |
| |
| EditText mAddressView; |
| |
| EditText mMediaView; |
| |
| TestTcpServer server; |
| |
| /** Called when the activity is first created. */ |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| Intent intent = getIntent(); |
| |
| String action = intent.getAction(); |
| |
| Context c = getBaseContext(); |
| |
| if (Intent.ACTION_SEND.equals(action)) { |
| /* |
| * Other application is trying to share a file via Bluetooth, |
| * probably Pictures, or vCard. The Intent should contain an |
| * EXTRA_STREAM with the data to attach. |
| */ |
| |
| String type = intent.getType(); |
| Uri stream = (Uri)intent.getParcelableExtra(Intent.EXTRA_STREAM); |
| |
| if (stream != null && type != null) { |
| /* |
| * if (MimeUtility.mimeTypeMatches(type, |
| * Email.ACCEPTABLE_ATTACHMENT_SEND_TYPES)) { |
| * addAttachment(stream); |
| */ |
| Log.v(Constants.TAG, " Get share intent with Uri " + stream + " mimetype is " |
| + type); |
| // Log.v(Constants.TAG, " trying Uri function " + |
| // stream.getAuthority() + " " + Uri.parse(stream)); |
| Cursor cursor = c.getContentResolver().query(stream, null, null, null, null); |
| cursor.close(); |
| |
| } |
| /* start insert a record */ |
| /* |
| * ContentValues values = new ContentValues(); |
| * values.put(BluetoothShare.URI, stream.toString()); |
| * values.put(BluetoothShare.DESTINATION, "FF:FF:FF:00:00:00"); |
| * values.put(BluetoothShare.DIRECTION, |
| * BluetoothShare.DIRECTION_OUTBOUND); final Uri contentUri = |
| * getContentResolver().insert(BluetoothShare.CONTENT_URI, values); |
| * Log.v(Constants.TAG, "insert contentUri: " + contentUri); |
| */ |
| } |
| /* |
| * Context c = getBaseContext(); c.startService(new Intent(c, |
| * BluetoothOppService.class)); |
| */ |
| |
| setContentView(R.layout.testactivity_main); |
| |
| Button mInsertRecord = (Button)findViewById(R.id.insert_record); |
| Button mDeleteRecord = (Button)findViewById(R.id.delete_record); |
| Button mUpdateRecord = (Button)findViewById(R.id.update_record); |
| |
| Button mAckRecord = (Button)findViewById(R.id.ack_record); |
| |
| Button mDeleteAllRecord = (Button)findViewById(R.id.deleteAll_record); |
| mUpdateView = (EditText)findViewById(R.id.update_text); |
| mAckView = (EditText)findViewById(R.id.ack_text); |
| mDeleteView = (EditText)findViewById(R.id.delete_text); |
| mInsertView = (EditText)findViewById(R.id.insert_text); |
| |
| mAddressView = (EditText)findViewById(R.id.address_text); |
| mMediaView = (EditText)findViewById(R.id.media_text); |
| |
| mInsertRecord.setOnClickListener(insertRecordListener); |
| mDeleteRecord.setOnClickListener(deleteRecordListener); |
| mUpdateRecord.setOnClickListener(updateRecordListener); |
| mAckRecord.setOnClickListener(ackRecordListener); |
| mDeleteAllRecord.setOnClickListener(deleteAllRecordListener); |
| |
| Button mStartTcpServer = (Button)findViewById(R.id.start_server); |
| mStartTcpServer.setOnClickListener(startTcpServerListener); |
| |
| Button mNotifyTcpServer = (Button)findViewById(R.id.notify_server); |
| mNotifyTcpServer.setOnClickListener(notifyTcpServerListener); |
| /* parse insert result Uri */ |
| /* |
| * String id = contentUri.getPathSegments().get(1); Log.v(Constants.TAG, |
| * "insert record id is " + id); Uri contentUri1 = |
| * Uri.parse(BluetoothShare.CONTENT_URI + "/" + id); |
| */ |
| /* update a single column of a record */ |
| /* |
| * ContentValues updateValues = new ContentValues(); |
| * updateValues.put(BluetoothShare.TOTAL_BYTES, 120000); |
| * getContentResolver().update(contentUri1,updateValues,null,null); |
| */ |
| /* query a single column of a record */ |
| /* |
| * Cursor queryC = getContentResolver().query(contentUri1, null, null, |
| * null, null); if (queryC != null) { if (queryC.moveToFirst()) { int |
| * currentByteColumn = |
| * queryC.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES); int |
| * currentByte = queryC.getInt(currentByteColumn); |
| */ |
| /* update a column of a record */ |
| /* |
| * for(int i =0;i<100;i++){ currentByte ++; |
| * updateValues.put(BluetoothShare.CURRENT_BYTES, currentByte); |
| * getContentResolver().update(contentUri1,updateValues,null,null); } } |
| * } |
| */ |
| /* query whole data base */ |
| /* |
| * Cursor c = managedQuery(contentUri1, new String [] {"_id", |
| * BluetoothShare.URI, BluetoothShare.STATUS, |
| * BluetoothShare.TOTAL_BYTES, BluetoothShare.CURRENT_BYTES, |
| * BluetoothShare._DATA, BluetoothShare.DIRECTION, |
| * BluetoothShare.MIMETYPE, BluetoothShare.DESTINATION, |
| * BluetoothShare.VISIBILITY, BluetoothShare.USER_CONFIRMATION, |
| * BluetoothShare.TIMESTAMP}, null, null, null); Log.v(Constants.TAG, |
| * "query " + contentUri1 +" get " + c.getCount()+" records"); |
| */ |
| /* delete a record */ |
| /* |
| * Uri contentUri2 = Uri.parse(BluetoothShare.CONTENT_URI + "/" + 1); |
| * getContentResolver().delete(contentUri2, null, null); |
| */ |
| |
| } |
| |
| public OnClickListener insertRecordListener = new OnClickListener() { |
| public void onClick(View view) { |
| |
| String address = null; |
| if (mAddressView.getText().length() != 0) { |
| address = mAddressView.getText().toString(); |
| Log.v(Constants.TAG, "Send to address " + address); |
| } |
| if (address == null) { |
| address = "00:17:83:58:5D:CC"; |
| } |
| |
| Integer media = null; |
| if (mMediaView.getText().length() != 0) { |
| media = Integer.parseInt(mMediaView.getText().toString().trim()); |
| Log.v(Constants.TAG, "Send media no. " + media); |
| } |
| if (media == null) { |
| media = 1; |
| } |
| ContentValues values = new ContentValues(); |
| values.put(BluetoothShare.URI, "content://media/external/images/media/" + media); |
| // values.put(BluetoothShare.DESTINATION, "FF:FF:FF:00:00:00"); |
| // baibai Q9 test |
| // values.put(BluetoothShare.DESTINATION, "12:34:56:78:9A:BC"); |
| // java's nokia |
| // values.put(BluetoothShare.DESTINATION, "00:1B:33:F0:58:FB"); |
| // Assis phone |
| // values.put(BluetoothShare.DESTINATION, "00:17:E5:5D:74:F3"); |
| // Jackson E6 |
| // values.put(BluetoothShare.DESTINATION, "00:1A:1B:7F:1E:F0"); |
| // Baibai V950 |
| // values.put(BluetoothShare.DESTINATION, "00:17:83:58:5D:CC"); |
| // Baibai NSC1173 |
| // values.put(BluetoothShare.DESTINATION, "00:16:41:49:5B:F3"); |
| |
| values.put(BluetoothShare.DESTINATION, address); |
| |
| values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_OUTBOUND); |
| |
| Long ts = System.currentTimeMillis(); |
| values.put(BluetoothShare.TIMESTAMP, ts); |
| |
| Integer records = null; |
| if (mInsertView.getText().length() != 0) { |
| records = Integer.parseInt(mInsertView.getText().toString().trim()); |
| Log.v(Constants.TAG, "parseInt " + records); |
| } |
| if (records == null) { |
| records = 1; |
| } |
| for (int i = 0; i < records; i++) { |
| Uri contentUri = getContentResolver().insert(BluetoothShare.CONTENT_URI, values); |
| Log.v(Constants.TAG, "insert contentUri: " + contentUri); |
| currentInsert = contentUri.getPathSegments().get(1); |
| Log.v(Constants.TAG, "currentInsert = " + currentInsert); |
| } |
| |
| } |
| }; |
| |
| public OnClickListener deleteRecordListener = new OnClickListener() { |
| public void onClick(View view) { |
| Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" |
| + mDeleteView.getText().toString()); |
| getContentResolver().delete(contentUri, null, null); |
| } |
| }; |
| |
| public OnClickListener updateRecordListener = new OnClickListener() { |
| public void onClick(View view) { |
| Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" |
| + mUpdateView.getText().toString()); |
| ContentValues updateValues = new ContentValues(); |
| // mCurrentByte ++; |
| // updateValues.put(BluetoothShare.TOTAL_BYTES, "120000"); |
| // updateValues.put(BluetoothShare.CURRENT_BYTES, mCurrentByte); |
| // updateValues.put(BluetoothShare.VISIBILITY, |
| // BluetoothShare.VISIBILITY_HIDDEN); |
| updateValues.put(BluetoothShare.USER_CONFIRMATION, |
| BluetoothShare.USER_CONFIRMATION_CONFIRMED); |
| getContentResolver().update(contentUri, updateValues, null, null); |
| } |
| }; |
| |
| public OnClickListener ackRecordListener = new OnClickListener() { |
| public void onClick(View view) { |
| Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" |
| + mAckView.getText().toString()); |
| ContentValues updateValues = new ContentValues(); |
| // mCurrentByte ++; |
| // updateValues.put(BluetoothShare.TOTAL_BYTES, "120000"); |
| // updateValues.put(BluetoothShare.CURRENT_BYTES, mCurrentByte); |
| updateValues.put(BluetoothShare.VISIBILITY, BluetoothShare.VISIBILITY_HIDDEN); |
| // updateValues.put(BluetoothShare.USER_CONFIRMATION, |
| // BluetoothShare.USER_CONFIRMATION_CONFIRMED); |
| getContentResolver().update(contentUri, updateValues, null, null); |
| } |
| }; |
| |
| public OnClickListener deleteAllRecordListener = new OnClickListener() { |
| public void onClick(View view) { |
| Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + ""); |
| getContentResolver().delete(contentUri, null, null); |
| } |
| }; |
| |
| public OnClickListener startTcpServerListener = new OnClickListener() { |
| public void onClick(View view) { |
| server = new TestTcpServer(); |
| Thread server_thread = new Thread(server); |
| server_thread.start(); |
| |
| } |
| }; |
| |
| public OnClickListener notifyTcpServerListener = new OnClickListener() { |
| public void onClick(View view) { |
| final Thread notifyThread = new Thread() { |
| public void run() { |
| synchronized (server) { |
| server.a = true; |
| server.notify(); |
| } |
| } |
| |
| }; |
| notifyThread.start(); |
| } |
| |
| }; |
| } |
| |
| /** |
| * This class listens on OPUSH channel for incoming connection |
| */ |
| class TestTcpListener { |
| |
| private static final String TAG = "BtOppRfcommListener"; |
| |
| private static final boolean D = Constants.DEBUG; |
| |
| private static final boolean V = Constants.VERBOSE; |
| |
| private volatile boolean mInterrupted; |
| |
| private Thread mSocketAcceptThread; |
| |
| private Handler mCallback; |
| |
| private static final int ACCEPT_WAIT_TIMEOUT = 5000; |
| |
| public static final int DEFAULT_OPP_CHANNEL = 12; |
| |
| public static final int MSG_INCOMING_BTOPP_CONNECTION = 100; |
| |
| private int mBtOppRfcommChannel = -1; |
| |
| public TestTcpListener() { |
| this(DEFAULT_OPP_CHANNEL); |
| } |
| |
| public TestTcpListener(int channel) { |
| mBtOppRfcommChannel = channel; |
| } |
| |
| public synchronized boolean start(Handler callback) { |
| if (mSocketAcceptThread == null) { |
| mCallback = callback; |
| mSocketAcceptThread = new Thread(TAG) { |
| ServerSocket mServerSocket; |
| |
| public void run() { |
| if (D) Log.d(TAG, "RfcommSocket listen thread starting"); |
| try { |
| if (V) |
| Log.v(TAG, "Create server RfcommSocket on channel" |
| + mBtOppRfcommChannel); |
| mServerSocket = new ServerSocket(6500, 1); |
| } catch (IOException e) { |
| Log.e(TAG, "Error listing on channel" + mBtOppRfcommChannel); |
| mInterrupted = true; |
| } |
| while (!mInterrupted) { |
| try { |
| mServerSocket.setSoTimeout(ACCEPT_WAIT_TIMEOUT); |
| Socket clientSocket = mServerSocket.accept(); |
| if (clientSocket == null) { |
| if (V) Log.v(TAG, "incomming connection time out"); |
| } else { |
| if (D) Log.d(TAG, "RfcommSocket connected!"); |
| Log.d(TAG, "remote addr is " |
| + clientSocket.getRemoteSocketAddress()); |
| TestTcpTransport transport = new TestTcpTransport(clientSocket); |
| Message msg = Message.obtain(); |
| msg.setTarget(mCallback); |
| msg.what = MSG_INCOMING_BTOPP_CONNECTION; |
| msg.obj = transport; |
| msg.sendToTarget(); |
| } |
| } catch (SocketException e) { |
| Log.e(TAG, "Error accept connection " + e); |
| } catch (IOException e) { |
| Log.e(TAG, "Error accept connection " + e); |
| } |
| |
| if (mInterrupted) { |
| Log.e(TAG, "socketAcceptThread thread was interrupted (2), exiting"); |
| } |
| } |
| if (D) Log.d(TAG, "RfcommSocket listen thread finished"); |
| } |
| }; |
| mInterrupted = false; |
| mSocketAcceptThread.start(); |
| |
| } |
| return true; |
| |
| } |
| |
| public synchronized void stop() { |
| if (mSocketAcceptThread != null) { |
| if (D) Log.d(TAG, "stopping Connect Thread"); |
| mInterrupted = true; |
| try { |
| mSocketAcceptThread.interrupt(); |
| if (V) Log.v(TAG, "waiting for thread to terminate"); |
| mSocketAcceptThread.join(); |
| mSocketAcceptThread = null; |
| mCallback = null; |
| } catch (InterruptedException e) { |
| if (V) Log.v(TAG, "Interrupted waiting for Accept Thread to join"); |
| } |
| } |
| } |
| |
| } |
| |
| class TestTcpServer extends ServerRequestHandler implements Runnable { |
| private static final String TAG = "ServerRequestHandler"; |
| |
| private static final boolean V = Constants.VERBOSE; |
| |
| static final int port = 6500; |
| |
| public boolean a = false; |
| |
| // TextView serverStatus = null; |
| public void run() { |
| try { |
| updateStatus("[server:] listen on port " + port); |
| TestTcpSessionNotifier rsn = new TestTcpSessionNotifier(port); |
| |
| updateStatus("[server:] Now waiting for a client to connect"); |
| rsn.acceptAndOpen(this); |
| updateStatus("[server:] A client is now connected"); |
| } catch (Exception ex) { |
| updateStatus("[server:] Caught the error: " + ex); |
| } |
| } |
| |
| public TestTcpServer() { |
| updateStatus("enter construtor of TcpServer"); |
| } |
| |
| public int onConnect(HeaderSet request, HeaderSet reply) { |
| |
| updateStatus("[server:] The client has created an OBEX session"); |
| /* sleep for 2000 ms to wait for the batch contains all ShareInfos */ |
| synchronized (this) { |
| try { |
| while (!a) { |
| wait(500); |
| } |
| } catch (InterruptedException e) { |
| if (V) Log.v(TAG, "Interrupted waiting for markBatchFailed"); |
| } |
| } |
| updateStatus("[server:] we accpet the seesion"); |
| return ResponseCodes.OBEX_HTTP_OK; |
| } |
| |
| public int onPut(Operation op) { |
| FileOutputStream fos = null; |
| try { |
| java.io.InputStream is = op.openInputStream(); |
| |
| updateStatus("Got data bytes " + is.available() + " name " |
| + op.getReceivedHeader().getHeader(HeaderSet.NAME) + " type " + op.getType()); |
| |
| File f = new File((String)op.getReceivedHeader().getHeader(HeaderSet.NAME)); |
| fos = new FileOutputStream(f); |
| byte b[] = new byte[1000]; |
| int len; |
| |
| while (is.available() > 0 && (len = is.read(b)) > 0) { |
| fos.write(b, 0, len); |
| } |
| |
| fos.close(); |
| is.close(); |
| updateStatus("[server:] Wrote data to " + f.getAbsolutePath()); |
| } catch (Exception e) { |
| if (fos != null) { |
| try { |
| fos.close(); |
| } catch (IOException e1) { |
| e1.printStackTrace(); |
| } |
| } |
| e.printStackTrace(); |
| } |
| return ResponseCodes.OBEX_HTTP_OK; |
| } |
| |
| public void onDisconnect(HeaderSet req, HeaderSet resp) { |
| updateStatus("[server:] The client has disconnected the OBEX session"); |
| } |
| |
| public void updateStatus(String message) { |
| Log.v(TAG, "\n" + message); |
| } |
| |
| public void onAuthenticationFailure(byte[] userName) { |
| } |
| |
| public int onSetPath(HeaderSet request, HeaderSet reply, boolean backup, boolean create) { |
| |
| return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; |
| } |
| |
| public int onDelete(HeaderSet request, HeaderSet reply) { |
| return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; |
| } |
| |
| public int onGet(Operation op) { |
| return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; |
| } |
| |
| } |
| |
| class TestTcpSessionNotifier { |
| /* implements SessionNotifier */ |
| |
| ServerSocket server = null; |
| |
| Socket conn = null; |
| |
| private static final String TAG = "TestTcpSessionNotifier"; |
| |
| public TestTcpSessionNotifier(int port) throws IOException { |
| server = new ServerSocket(port); |
| } |
| |
| public ServerSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth) |
| throws IOException { |
| try { |
| conn = server.accept(); |
| |
| } catch (Exception ex) { |
| Log.v(TAG, "ex"); |
| } |
| |
| TestTcpTransport tt = new TestTcpTransport(conn); |
| |
| return new ServerSession((ObexTransport)tt, handler, auth); |
| |
| } |
| |
| public ServerSession acceptAndOpen(ServerRequestHandler handler) throws IOException { |
| |
| return acceptAndOpen(handler, null); |
| |
| } |
| |
| } |
| |
| class TestTcpTransport implements ObexTransport { |
| |
| Socket s = null; |
| |
| public TestTcpTransport(Socket s) { |
| super(); |
| this.s = s; |
| } |
| |
| public void close() throws IOException { |
| s.close(); |
| } |
| |
| public DataInputStream openDataInputStream() throws IOException { |
| return new DataInputStream(openInputStream()); |
| } |
| |
| public DataOutputStream openDataOutputStream() throws IOException { |
| return new DataOutputStream(openOutputStream()); |
| } |
| |
| public InputStream openInputStream() throws IOException { |
| return s.getInputStream(); |
| } |
| |
| public OutputStream openOutputStream() throws IOException { |
| return s.getOutputStream(); |
| } |
| |
| public void connect() throws IOException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void create() throws IOException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void disconnect() throws IOException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void listen() throws IOException { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public boolean isConnected() throws IOException { |
| return s.isConnected(); |
| } |
| |
| } |